I'm trying to create a simple form that, upon hitting the 'enter' key, the entered data will be sent and appended to a list in my controller. The code I have is as follows:
controller.js
.controller('GenericTodosCtrl', function($scope) {
$scope.todos=[];
$scope.newTodo="";
function addTodo() {
alert("hello");
$scope.todos.push({
content: $scope.newTodo,
done: false,
editing: false
});
$scope.newTodo = "";
};
});
main.html
<form ng:submit="addTodo()">
<input name="newTodo" placeholder="Placeholder" type="text">
</form>
Currently, when I type in values and hit 'enter' nothing happens (not even the alert). I can't seem to figure out if I should be using "this" instead of $scope for things in controller.js. Does ng:submit require something in the ? Or is this an issue with my javascript instead?
You should make addTodo part of your $scope.
$scope.addTodo = function() {
alert("hello");
$scope.todos.push({
content: $scope.newTodo,
done: false,
editing: false
});
$scope.newTodo = "";
};
Also, make sure the value in the input field is actually databound to your $scope value by using ngModel:
<form ng:submit="addTodo()">
<input ng:model="newTodo" placeholder="Placeholder" type="text">
</form>
Related
See Fiddle: http://jsfiddle.net/hejado/7bqjqc2w/
I'm trying to form.reset() my form using angular.
HTML:
<div ng-controller="formCtrl">
<form name="resetme" id="resetme">
<input ng-model="text" type="text" />
<input file-model="file" type="file" />
<button type="button" ng-click="resetForm()">reset</button>
</form>
</div>
JS:
.controller('formCtrl', function($scope) {
$scope.resetForm = function() {
//$scope.resetme.reset();
document.getElementById('resetme').reset();
};
});
Please note: I'm using this kind of form to ajax-upload a file. The page is not refreshing and I don't want to use any reset-buttons. (I'm using one in the fiddle for simplicity.) I want to call the reset-function after the fileupload is finished (via http success).
I'm using
<input type="file" />
so I can't reassign empty values to all my inputs, because file inputs are readonly.
Calling the reset() function on the DOM element works, but I was told talking to the DOM in angular would be evil, so...
I'd like to know, how this would be done the angular way. I tried naming the form and referencing it via $scope.formname but I'm not able to call Web API functions... (commented line)
How can I achieve this?
UPDATE
After reading some of the answers, I should make clear, that I am using ngModel and a custom directive fileModel to get a hold of the file-object.
Some of the solutions worked in resetting the value of the input field, but the model is not cleared (neither file, nor text). Custom directives are the answer to that, but this kinda exceeds the scope of this question.
I wrote about this topic a couple years ago. I don't know if the Angular team has yet implemented a native form reset directive but you can do so yourself. There are a couple caveats to this implementation: it only works for one model (if you need to support more see the followup post) and the issue of when to initialize the original values. Also, I never tested this with file inputs so I am not sure it would work with those.
There was an issue for this but it was closed due to inactivity. :/
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', ['$scope',
function($scope) {
$scope.myModel = {
foo: 'Boop',
bar: 'Beep'
};
$scope.myModelCopy = angular.copy($scope.myModel);
}
]);
myApp.directive('resetDirective', ['$parse',
function($parse) {
return function(scope, element, attr) {
var fn = $parse(attr.resetDirective);
var masterModel = angular.copy(fn(scope));
// Error check to see if expression returned a model
if (!fn.assign) {
throw Error('Expression is required to be a model: ' + attr.resetDirective);
}
element.bind('reset', function(event) {
scope.$apply(function() {
fn.assign(scope, angular.copy(masterModel));
scope.form.$setPristine();
});
// TODO: memoize prevention method
if (event.preventDefault) {
return event.preventDefault();
} else {
return false;
}
});
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
<form reset-directive="myModel" name="form">
<input type="text" ng-model="myModel.foo" />
<input type="text" ng-model="myModel.bar" />
<input type="reset" value="Reset" />
<pre>myModel: {{ myModel | json }}</pre>
<pre>myModelCopy: {{ myModelCopy | json }}</pre>
<pre>form pristine: {{ form.$pristine }}</pre>
</form>
</div>
</body>
You can try :
reset
$scope.resetForm = function(form) {
//Even when you use form = {} it does not work
form.fieldA = null;
form.fieldB = null;
///more fields
}
Or
$scope.resetForm = function(form) {
//Even when you use form = {} it does not work
angular.copy({},form);
}
See Demo
You'd want to attach ng-model to each of your input fields then null them out via $scope. Either that or make a custom directive
I've just had a similar problem with forms not resetting. Here's what I would do:
In your resetform() function, I would include statements that set both of your ng-models in your input to "". For example:
**HTML**
<input ng-model="text" type="text" />
<input file-model="file" type="file" />
**JS**
.controller('formCtrl', function($scope) {
$scope.resetForm = function() {
$scope.text = "";
$scope.file = null;
};
});
Not certain if this will work for file-models but I'm certain it will remove the text. Best of luck!
If you don't want to use ng-model and proper reset type of button you can use this code, however this is not proper angular way to reset the form but it will work
$scope.reset = function(){
$('form').children('*').each(function(){
$(this).val('');
});
}
Here's the Plunker
To reset the form data use following code :
$scope.resetEmployeeData = function() {
$scope.employeeCred.userName = '';
$scope.employeeCred.employeeNo = '';
$scope.employeeCred.sapNo = '';
$scope.employeeCred.emailD = '';
$scope.employeeCred.mobileNo = '';
**this**.createEmployee.$setPristine();
**this**.createEmployee.$setUntouched();
};
use this rather than $scope.
I'm still fairly new to angular.js. This seems like it should be very simple, but I'm stumped.
I have an input field:
<input type="text" placeholder="Search" ng-model="search.txt">
And I have a button that calls this function in my controller on ng-click:
$scope.clearSearch = function() {
$scope.search = {txt:"qqqqq"};
}
Clicking the button behaves as expected - the input value on the page becomes "qqqqq". So the data binding seems correct.
However, if I type anything into the field first and then press the button, the input value does not change on the page - the input field keeps the value I typed. Why is that?
What I'm really trying to do is clear the field, I'm just using "qqqqq" for illustration - setting the value to null has the same behavior.
It works:
Script:
angular.module('myapp',[])
.controller('myctrl',function($scope){
$scope.search = {text:'some input'};
$scope.clearSearch = function () {
$scope.search={text:null};
}
});
Markup:
<div ng-app="myapp" ng-controller="myctrl">
<input type="text" ng-model="search.text"/>
<button ng-click="clearSearch()">clear</button>
</div>
In plunker
I've got a problem with a form. I'm submitting the form and some of the fields don't have to be filled, when the data is send to a restful API I see that angular doesn't pick up the empty, never touched, never changed, input fields.
But on the server side the field is expected to be present. How can I get angular to send these fields as well?
I have two inputs (data.Record.one, data.Record.two), when I fill one and submit the form I'm ending up with this:
{
"Record": {
"one": "test"
}
}
I guess this is because angular doesn't "see" untouched and empty fields.
But I want that:
{
"Record": {
"one": "test",
"two": ""
}
}
Here is a demo of what I try: http://plnkr.co/edit/Ky0PQ9U5o1V7IyU9QgkK
I'm well aware that I could initialize the form with an empty skeleton object but I would really prefer to not have to do that. If I need to do that it's just additional code that as a bonus will just introduce an area of potential fail if another dev adds a field in the form but forgets / doesn't know about the skeleton in the JS code.
Angular treats empty fields as empty/null by default. You can disable this by adding ng-trim="false" on your input fields.
This will not add extra code, only definition on your markup.
https://docs.angularjs.org/api/ng/input/input%5Btext%5D
EDIT: I see now what you want. Angular takes good care of your model (data). Just because you bind an input field to a sub,sub property won't initialize the property with empty string. The input fields does not contain empty string - they contain null which is what you put in them in the first place (by binding them to an uninitalized property).
The feature you want, is for angular to initialize your data.Record with the properties you need. You could make a custom directive for that called initialize-property that would set its model to an empty string.
EDIT: I created the directive but plunker won't let me access due to some cross domain problems. You should be able to use it in your own work though
myApp.directive('initializeProperty', function() {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.val('');
}
};
});
And then on your input fields use this:
One <input name="one" ng-model="data.Record.one" initialize-property ng-trim="false" /><br />
Two <input name="one" ng-model="data.Record.two" initialize-property ng-trim="false" /><br />
replace your app.js code to this one
var myApp = angular.module('myApp', []);
myApp.controller('TestFormController', ['$scope', '$log', function($scope, $log) {
$scope.data = {
Record : {
"one": "",
"two": ""
}
}
$scope.add = function() {
$log.log($scope.data);
}
}]);
DEMO
UPDATE !
change your view with this html
One <input name="one" ng-init="data.Record.one = ''" ng-model="data.Record.one" /><br />
Two <input name="one" ng-init="data.Record.two = ''" ng-model="data.Record.two" /><br />
i have added extra ng-init directive which will initilize your data
DEMO
I fixed it simply using ng-init="inputfieldname=''"
I had the same problem, so then in my research I find this:
http://blog.fernandomantoan.com/angularjs-forcando-bind-de-todos-os-campos-no-submit/
Solve my problem, but I had to edit, thus:
.directive('forceBind', function() {
return {
require: '^form',
priority: -1,
link: function (scope, element, attrs, form) {
element.bind('submit', function() {
angular.forEach(form, function(value, key) {
if(typeof value == 'object'){
if (value.hasOwnProperty('$modelValue')) {
if (!value.$viewValue) {
value.$setViewValue("");
}
}
}
});
});
}
};
});
So, when the event submit runs, before entering in method the directive force bind.
I recommend using ng-submit for validation.
Sorry my english.
I have a simple login form which works just peachy unless you use Chrome's auto complete feature.
If you start typing and use the auto complete feature and it auto populates your password, my angularjs model does not have any value for the password.
I tried to turn autocomplete off by setting the attribute on the form autocomplete="off" but that doesn't seem to have any effect.
How can I either:
1. Ensure that I can get the value if someone uses Chrome's auto-complete feature?
2. Disable Chrome's auto-complete feature?
<form class="form-signin" name="form" ng-submit="login()" autocomplete="off">
<h3>Login</h3>
<input type="email" name="email" class="form-control" placeholder="Email address" ng-model="user.email" required autofocus>
<input type="password" name="password" class="form-control" placeholder="Password" ng-model="user.password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
From the link added in the comment:Github Issue's
// Due to browsers issue, it's impossible to detect without a timeout any changes of autofilled inputs
// https://github.com/angular/angular.js/issues/1460
// https://github.com/angular/angular.js/issues/1460#issuecomment-28662156
// Could break future Angular releases (if use `compile()` instead of `link())
// TODO support select
angular.module("app").config(["$provide", function($provide) {
var inputDecoration = ["$delegate", "inputsWatcher", function($delegate, inputsWatcher) {
var directive = $delegate[0];
var link = directive.link;
function linkDecoration(scope, element, attrs, ngModel){
var handler;
// By default model.$viewValue is equals to undefined
if(attrs.type == "checkbox"){
inputsWatcher.registerInput(handler = function(){
var value = element[0].checked;
// By default element is not checked
if (value && ngModel.$viewValue !== value) {
ngModel.$setViewValue(value);
}
});
}else if(attrs.type == "radio"){
inputsWatcher.registerInput(handler = function(){
var value = attrs.value;
// By default element is not checked
if (element[0].checked && ngModel.$viewValue !== value) {
ngModel.$setViewValue(value);
}
});
}else{
inputsWatcher.registerInput(handler = function(){
var value = element.val();
// By default value is an empty string
if ((ngModel.$viewValue !== undefined || value !== "") && ngModel.$viewValue !== value) {
ngModel.$setViewValue(value);
}
});
}
scope.$on("$destroy", function(){
inputsWatcher.unregisterInput(handler);
});
// Exec original `link()`
link.apply(this, [].slice.call(arguments, 0));
}
// Decorate `link()` don't work for `inputDirective` (why?)
/*
directive.link = linkDecoration;
*/
// So use `compile()` instead
directive.compile = function compile(element, attrs, transclude){
return linkDecoration;
};
delete directive.link;
return $delegate;
}];
$provide.decorator("inputDirective", inputDecoration);
$provide.decorator("textareaDirective", inputDecoration);
//TODO decorate selectDirective (see binding "change" for `Single()` and `Multiple()`)
}]).factory("inputsWatcher", ["$interval", "$rootScope", function($interval, $rootScope){
var INTERVAL_MS = 500;
var promise;
var handlers = [];
function execHandlers(){
for(var i = 0, l = handlers.length; i < l; i++){
handlers[i]();
}
}
return {
registerInput: function registerInput(handler){
if(handlers.push(handler) == 1){
promise = $interval(execHandlers, INTERVAL_MS);
}
},
unregisterInput: function unregisterInput(handler){
handlers.splice(handlers.indexOf(handler), 1);
if(handlers.length == 0){
$interval.cancel(promise);
}
}
}
}]);
From: Developer.mozilla.org docs Turning_off_form_autocompletion
If an author would like to prevent the auto-filling of password fields
in user management pages where a user can specify a new password for
someone other than themselves, autocomplete="new-password" should be
specified, though support for this has not been implemented in all
browsers yet.
So, what makes it work for me:
set autocomplete="new-password" on the password field
set autocomplete="off" in the username field.
I hope that it works for you too :)
As said here, https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form
The Google Chrome UI for auto-complete requests varies, depending on
whether autocomplete is set to off on input elements as well as their
form. Specifically, when a form has autocomplete set to off and its
input element's autocomplete field is not set, then if the user asks
for autofill suggestions for the input element, Chrome might display a
message saying "autocomplete has been disabled for this form." On the
other hand, if both the form and the input element have autocomplete
set to off, the browser will not display that message. For this
reason, you should set autocomplete to off for each input that has
custom auto-completion.
You need to set autocomplete="off" on both form and input
I don't think this is related to AngularJS
I had the same issue and found a very simple solution that just uses jQuery to grab the value on submit. In my controller I have the following:
$scope.username = "";
$scope.password = "";
$scope.login = function(){
$scope.username = $("#username").val();
$scope.password = $("#password").val();
// Proceed as normal
};
There are some downsides, if you need to do validation etc but otherwise it's fine for smaller forms like this.
You could watch the email field value and everytime the value in that field is changing, you could trigger a "change"-event on the password field. This events trigger all the ng-model magic on that field and updates the model.
module.directive("autocompleteFor", function () {
return {
restrict: "A",
link: function ($scope, $element, $attrs) {
$scope.$watch($attrs.autocompleteFor, function () {
$element.triggerHandler("change");
})
}
}
});
With this directive you could handle that scenario like this:
<input type="email" name="email" ng-model="user.email">
<input type="password" autocomplete-for="user.email" name="password" ng-model="user.password" required>
-----------------------------
To disable the autocomplete/autofill from a input, just type:
- autocomplete="false" instead of autocomplete="off"!
Below directive worked for me. It's simple and clean fix. Hope that helps!
Ref: AngularJS browser autofill workaround by using a directive
Here is a solution that is far less hacky than other solutions presented and is semantically sound AngularJS: VictorBlog.com
myApp.directive('formAutofillFix', function() {
return function(scope, elem, attrs) {
// Fixes Chrome bug: https://groups.google.com/forum/#!topic/angular/6NlucSskQjY
elem.prop('method', 'POST');
// Fix autofill issues where Angular doesn't know about auto-filled inputs
if(attrs.ngSubmit) {
setTimeout(function() {
elem.unbind('submit').submit(function(e) {
e.preventDefault();
elem.find('input, textarea, select').trigger('input').trigger('change').trigger('keydown');
scope.$apply(attrs.ngSubmit);
});
}, 0);
}
};
});
Then you simply attach the directive to your form:
<form ng-submit="submitLoginForm()" form-autofill-fix>
<div>
<input type="email" ng-model="email" ng-required />
<input type="password" ng-model="password" ng-required />
<button type="submit">Log In</button>
</div>
</form>
alternative solution is just to get rid off form element and use ng-form instead, it disables all browser interferings
<div ng-form="yourFormName" class="form-signin" ng-submit="login()">
Old question, but whatever
I came across the same problem and I've got a small "hack" solution. This problem happened at many different places in my app, so I created a directive for reusability.
module.directive("fakeAutocomplete", [
function () {
return {
restrict: "EA",
replace: true,
template: "<div><input/><input type=\"password\"/></div>",
link: function (scope, elem, attrs) {
elem.css({
"overflow": "hidden",
"width": "0px",
"height": "0px"
});
}
}
}
]);
And simply add
<fake-autocomplete></fake-autocomplete>
At the beginning of your form and the browser will detect the fake fields as the ones that should autocomplete. Simply putting display:none on the fields also does not seem to work anymore, I've tested it.
In my case, i set property autocomplete="off" in form and input.
<form autocomplete="off">
<input type="text" autocomplete="off">
</form>
It could be much simpler solution to the problem.
Angularjs couldn't "see" the value
Take the value via DOM (jQuery) then put it back into Angularjs.
```
angular.module('someModule').directive('chromeAutofillHack', function()
{
return {
require: '^ngModel',
restrict: 'A',
priority: 500, // set higher priority then other custom directives
link: function(scope, element, attrs , ngModelCtrl)
{
ngModelCtrl.$parsers.unshift(function(email)
{
if (!email) { // only do this when angular think there is no value
email = $(element).val();
ngModel.$setViewValue(email);
}
return email;
});
}
};
});
```
--- NO LONGER RELEVANT ---
I was able to disable autocomplete (weirdly enough) by adding the following.
<form ... novalidate>
<input ... formnovalidate />
Reference this Plunker
My solution for Chrome 35.0, Firefox 30.0, angular 1.2.18 (login page with password manager, autofill, angular method and redirect):
How does browser know when to prompt user to save password?
I ended up with a different solution that I don't see here yet. From what I found, the password value isn't exposed to the model (or possibly even the js api) until the user interacts with the page. Clicking the login button is enough interaction to make the value available, and the data binding will succeed early enough for the click handler on the button to access the password from the model. So if I could detect that the browser has auto-filled, I could enable the login button even though my model hadn't been updated yet. So I wrote a simple helper service to see if Chrome has auto-filled any inputs:
utilApp.service('autoFillDetectionService', [function () {
return {
hasAutoFillInputs: function () {
try{
return !!$(':-webkit-autofill').length;
}
catch (x) {
// IE gets here, it/jquery complains about an invalid pseudo-class
return false;
}
}
};
}]);
From the login controller, I have an interval checking if any input fields are marked as autofill and if so enable the login button.
Just Replace autocomplete="off" with autocomplete="new-password".
I have a reset function in angular to clear all the fields in a form. If I do something like:
reset
$scope.resetForm = function() {
$scope.someForm = {};
}
Everything works fine. But I want to use this function for multiple forms on the site. If I pass the form object in like:
reset
$scope.resetForm = function(form) {
$scope.form = {};
}
Then it won't work. Can someone explain to me why this would be happening?
You have 2 problems:
You're not accessing the passed in variable, still access the someForm of current scope.
When you pass parameter to the function, it's passed by reference. Even when you use form = {}, it does not work because it only changes the reference of the parameter, not the reference of the passed in someForm.
Try:
$scope.resetForm = function(form) {
//Even when you use form = {} it does not work
form.fieldA = null;
form.fieldB = null;
///more fields
}
Or
$scope.resetForm = function(form) {
//Even when you use form = {} it does not work
angular.copy({},form);
}
instead of:
$scope.resetForm = function(form) {
$scope.form = {};
}
In your plunk, I see that you're not separating the view from the model. You should do it for separation of concerns and to avoid problems that might happen when you clear all the fields (including DOM form object's fields).
<form name="form2" ng-controller="SecondController">
<label for="first_field">First Field</label>
<input ng-model="form2Model.first_field" />
<br />
<label for="second_field">Second Field</label>
<input ng-model="form2Model.second_field" />
<br />
Reset the form
</form>
http://plnkr.co/edit/x4JAeXra1bP4cQjIBld0?p=preview
You can also do:
form.fieldA = undefined;
It works great for radio buttons and checkboxes.
you can try this :
Deploy your function inside form button reset , in this way ...
<input type ="button" ng-click="Object.field1 = null; ObjectN.fieldN = null;" value="Reset" />