I been struggling to reset form once form is submitted. Someone posted this Here which I want to make it work but no success. Here is my My Code Example.
$scope.form.$setPristine(); is not setting Pristine: {{user_form.$pristine}} to true. See example above.
$setPristine() was introduced in the 1.1.x branch of angularjs. You need to use that version rather than 1.0.7 in order for it to work.
See http://plnkr.co/edit/815Bml?p=preview
Had a similar problem, where I had to set the form back to pristine, but also to untouched, since $invalid and $error were both used to show error messages. Only using setPristine() was not enough to clear the error messages.
I solved it by using setPristine() and setUntouched().
(See Angular's documentation: https://docs.angularjs.org/api/ng/type/ngModel.NgModelController)
So, in my controller, I used:
$scope.form.setPristine();
$scope.form.setUntouched();
These two functions reset the complete form to $pristine and back to $untouched, so that all error messages were cleared.
Just for those who want to get $setPristine without having to upgrade to v1.1.x, here is the function I used to simulate the $setPristine function. I was reluctant to use the v1.1.5 because one of the AngularUI components I used is no compatible.
var setPristine = function(form) {
if (form.$setPristine) {//only supported from v1.1.x
form.$setPristine();
} else {
/*
*Underscore looping form properties, you can use for loop too like:
*for(var i in form){
* var input = form[i]; ...
*/
_.each(form, function (input) {
if (input.$dirty) {
input.$dirty = false;
}
});
}
};
Note that it ONLY makes $dirty fields clean and help changing the 'show error' condition like $scope.myForm.myField.$dirty && $scope.myForm.myField.$invalid.
Other parts of the form object (like the css classes) still need to consider, but this solve my problem: hide error messages.
There is another way to pristine form that is by sending form into the controller. For example:-
In view:-
<form name="myForm" ng-submit="addUser(myForm)" novalidate>
<input type="text" ng-mode="user.name"/>
<span style="color:red" ng-show="myForm.name.$dirty && myForm.name.$invalid">
<span ng-show="myForm.name.$error.required">Name is required.</span>
</span>
<button ng-disabled="myForm.$invalid">Add User</button>
</form>
In Controller:-
$scope.addUser = function(myForm) {
myForm.$setPristine();
};
DavidLn's answer has worked well for me in the past. But it doesn't capture all of setPristine's functionality, which tripped me up this time. Here is a fuller shim:
var form_set_pristine = function(form){
// 2013-12-20 DF TODO: remove this function on Angular 1.1.x+ upgrade
// function is included natively
if(form.$setPristine){
form.$setPristine();
} else {
form.$pristine = true;
form.$dirty = false;
angular.forEach(form, function (input, key) {
if (input.$pristine)
input.$pristine = true;
if (input.$dirty) {
input.$dirty = false;
}
});
}
};
I solved the same problem of having to reset a form at its pristine state in Angular version 1.0.7 (no $setPristine method)
In my use case, the form, after being filled and submitted must disappear until it is again necessary for filling another record. So I made the show/hide effect by using ng-switch instead of ng-show. As I suspected, with ng-switch, the form DOM sub-tree is completely removed and later recreated. So the pristine state is automatically restored.
I like it because it is simple and clean but it may not be a fit for anybody's use case.
it may also imply some performance issues for big forms (?) In my situation I did not face this problem yet.
Related
in my Angular 1.x app I am getting a list of Offers via an api call to my backend.
For each Offer returned in the reply I am creating an ng-form. I then display the forms in a modal and I want to be able to disable each form's submit button when it has been clicked to avoid multiple clicks whilst the form data is posted to the back end.
This seems tricky since the number of Offers is an unknown, therefore I'm not sure how I can initialize a variable for each Offer in order to disable the button.
The task would be far more straight forward if I just had one single form, I colud set:
$scope.disableButton = true
... then use ng-disabled on the button
Thusfar I am displaying my forms as follows:
<div ng-form ng-repeat="i in offers track by $index" name="messageForm[$index]" class="row ng-cloak">
....
<button type="button" ng-click="offerRespond(messageForm[$index])" ng-disabled="!messageForm[$index].$valid || offer.i.disableButtons">Submit</button>
</div>
Then in my controller's offerRespond function:
offer = this;
offer.i.disableButtons = true;
This doesn't work of course but it is as close as I can get.
A hack would be to parse the Offers object before passing it to the frontend but that just seems like a horrible hack.
Actually I almost had the answer in my implementation, I just was referring to my variables in correctly:
ng-disabled="!messageForm[$index].$valid || offer.i.disableButtons"
should have been
ng-disabled="!messageForm[$index].$valid || i.disableButtons"
Thanks to #igor for giving me an idea to test which enabled me to revealed the answer myself.
I'm using Angular 1.5.9
I have a big form, which I scattered through different Bootstrap Accordion.
When there is an error in the form, I want to be able to change the class of my accordions to show in which accordions the error is located.
To check for errors in a whole form, I can check
myFormName.$error
And to check errors for an element, I can simply do
myFormName.myInputName.$error
But I don't know if there is a way to do this for multiple element at once, without having to check each element individually.
My first thought was to change the name of my inputs like so:
<input name="accordion1.fieldName">
But this didn't give me the expected result: I don't have myFormName.accordion1.$error, actually, I don't even have myFormName.accordion1.fieldName, since my data is actually stored in myFormName['accordion1.fieldName'] which is pretty much useless.
Has anyone found an answer to this problem? I think I'll have to check each field, which is kinda ugly, and a mess to maintain whenever we add / remove fields...
Maybe there is a directive out there that could do that for me, but as a non-native English speaker, I can't find which key words to use for my search in this situation.
One approach is to nest with the ng-form directive:
<form name=form1>
<div ng-form=set1>
<input name=input1 />
<input name=input2 />
</div>
</form>
{{form1.set1.$error}}
You could name the fields with a prefix such as 'accordion1_' then add a controller function that will filter your fields.
ctrl.fieldGroup = function(form, fieldPrefix) {
var fieldGroup = {};
angular.forEach(form, function(value, key) {
if (key.indexOf(prefix) === 0) {
fieldGroup[key] = value;
}
});
return fieldGroup;
}
Then ctrl.fieldGroup('accordion1') will return an object with the appriopriate fields on it. You could extend the function further to add an aggregate $error property to the resulting fieldGroup object.
Basic problem is, when user tabs in a specific text input on a form, prefilled "+36" gets selected. I'd like to somehow put the cursor right after it (after the +36), instead of selecting the whole word. I've been thinking about disabling text selection of text inputs but no result yet. Googled a lot for it but couldnt find anything but disabling text selection on web pages, which is not really related. How could I solve this problem?
If you are using Jquery, you can try something like this on document ready
$(document).ready(function() {
$("input").focus(function() {
var input = this;
setTimeout(function() {
input.selectionStart = input.selectionEnd;
}, 1);
});
});
Please find the Jsfiddle for the same Jsfiddle Input Focus
In your form element put autocomplete attribute like below
<form method="post" action="/form" autocomplete="off">
</form>
I'd like to create a form with checkboxes. At first it shouldnt be possible to check them. Then if you click submit they should be.
I got it working so its not clickable first with
function(e){ e.preventDefault(); }
But how do i make them clickable again after that?
That means you just want to go the the default behavior what you have removed first time. To this this you just have to do
function(e){ return true; }
Hope this work.
Easiest would be to disable the checkbox, then re-enable it when you're ready:
<input id="chk1" type="checkbox" disabled>
document.getElementById("chk1").removeAttribute("disabled");
If you're using jQuery, it would be easier to work with multiple checkboxes, and the syntax would be:
jQuery("#chk1").prop("disabled", false);
If you set your click handler to a function, just have that function prevent the click, depending on whether or not you want the boxes enabled. In your case, you said when the submit button was clicked, you want to start allowing them:
var _checkBoxesEnabled = false;
function checkBoxClicked(e) {
if (!_checkBoxesEnabled) {
e.preventDefault();
}
}
function submitButtonClicked() {
_checkBoxesEnabled = true;
}
Watch out for cross-browser compatibility - I'm spoiled by jQuery, so I don't remember exactly how the e in click handlers work with old IE versions using regular javascript.
I have the following code:
<form class="form"
data-ng-submit="modalSubmit(modal.data)"
id="modal-body"
name="modalForm"
novalidate>
This works and when I click on a button of type submit then the modalSubmit function is called.
However I would like to do this in my controller:
$scope.modalForm.$setPristine();
But it gives an error saying:
has no method '$setPristine'
How I can I set the form to pristine? I did try adding data-ng-form="modalForm" but then I get
a message saying something to the effect of duplicate directive names.
I tried changing the form element to a DIV but then the clicking on the submit button does not call
the function
Here's an example (modified from another user) that shows what I am trying to do which is set values to pristine:
plnkr.co/edit/LNanJdAggMLIgxii0cfv?p=preview
You're not doing anything wrong there, only problem is you're referencing an old version of angular in which $setPristine() was not a feature. $setPristine() was added in 1.1.+, so reference a newer version of angular and you're good to go. See it working in this plunk, using 1.2.+.
If you can't upgrade, then a dirty workaround would be to loop through all inputs in the form and set their $dirty and $pristine values manually:
$scope.mp = function() {
$scope.mainForm.$pristine=true;//clean main form
$scope.mainForm.$dirty=false;
angular.forEach($scope.mainForm,function(input){//clean all input controls
if (input !== undefined && input.$dirty !== undefined) {
input.$dirty=false;
input.$pristine=true;
}
});
}
First, your version of angular was old, 1.2.12 is the latest stable on the CDN. But even it wouldn't allow $setPristine because of the HTML5 validation that was going on.
The biggest problem was you used required on the fields instead of ng-required. The browser was doing the form validation for you instead of angular. You could also add the novalidate attribute to the form tag.
http://plnkr.co/edit/l1mUCceSFMFFZWgGgL6u?p=preview
it has already been implemented in this link you can use it this was as it has been demonstrated in the plnkr link.
As you can see from the above description, $setPristine only changes the state of the form (and thereby resets the css applied to each control in the form).
If you want to clear the values of each control, then you need to do for each in code.