Get pristine value for form element in Angular - angularjs

Does Angular have anything built in that returns the pristine value of an input element?
I see that there's a $setPristine(), but there's no function to get the pristine value? Right now, I just create a copy of the pristine value in my controller when the controller initializes. I really can't believe that's correct—that there isn't anything that will give me the original form field's value.
The form field is dirty but the value is the same as it was when the form field was pristine. The user has dirtied the field, but when the user leaves the field, the value is the same as it was before the field was dirtied. What does Angular provide that will tell me that?

When your input element is dirty angular applies the ng-dirty class to it. You can check to see if this class is present on the element. It also applies the ng-pristine class on the element before it has been changed.
One thing to note: if you change the models value and set it back to it's original value, it will still be dirty. That tripped me up a bit.

not sure I understood what you're asking. but if you want to check if the element is clean or dirty just $scope.formName.inputName.$dirty (or $pristine) this will return true or false accordingly.
and if you want the value...well thats also simple :)

Related

angularJS $dirty when value unchanged

I have a form with multiple fields that the user can alter. I need to keep track of the state of the field and only allow the user to save if the value is changed. Now it looks like $dirty is set to true the moment when the value is altered even if it were changed back to the original value. Is there any way to use $dirty or something similar to be true only if the value is changed from it's original value?
*edit: okay it doesn't seem like it's possible with built in functions. Would I be better off storing all the original values? I'd avoid using $watch.
Angular FormController doesn't have any property you can use to achieve this. $dirty can only tell you if user has already interacted with the form. You have to watch the value and 'manually' check if it has changed.
use $pristine No fields have been modified yet

Custom validator directive combined with other directive fires multiple times

I have a custom validation directive iban which checks if the value is a valid (Dutch) IBAN. That validator needs the value to be uppercased. I also have an uppercase directive which changes a value to uppercase. I want to combine both on one input element:
<input type="text" ng-model="iban" name="iban" capitalize="" iban="" />
I've created a jsfiddle demonstrating the situation.
I am struggling with the correct order of execution. If the user types in a value, I want capitalize to fire first, so the iban validator receives an uppercased value. If the model value is set from code, I also want to uppercase it first.
When the user types in a lowercase character, the uppercase directive calls ctrl.$setViewValue to set the view value. This triggers another run through the parsers. So both the uppercase directive and the iban directive are executed twice. The console log shows:
parsers.capitalize: nL12HHBA0429672071
uppercasing: nL12HHBA0429672071 => NL12HHBA0429672071, setting view value
parsers.capitalize: NL12HHBA0429672071
uppercasing: NL12HHBA0429672071 already uppercased
parsers.iban: NL12HHBA0429672071
setting validity to: true
returning NL12HHBA0429672071
parsers.iban: NL12HHBA0429672071
setting validity to: true
returning NL12HHBA0429672071
I would think it is not the intention to loop through your parsers multiple times.
Another problem is when I set the value from code to an invalid IBAN that's already uppercased (last link in my fiddle). In that case, the uppercase directive won't have to do anything. The iban directives formatter will set validity to false, and just return the value. If it's an lowercase invalid IBAN, the uppercase directive will call setViewValue, causing the IBAN directives parser code to execute which will return undefined. so that situation will change the model's value to undefined.
Am I making things too complicated? Should I try to create just an iban directive which will make sure that an uppercased value gets stored in the model when the user enters a valid lowercased iban value? Should I just keep the lowercased value in the model if it set from code? And maybe just use style="text-transform: uppercase" on the element to always show the value as if it is uppercased? A disadvantage would be that if the model is set to a valid but lowercased value, the form will show the uppercased value, which would be valid, while the model value is actually invalid.
There is definitely some complexity here. And in playing around with, there is some Angular weirdness as well (at least in my eyes - I'll get to that).
One complexity introduced here is that your capitalize $formatter actually changes the model value. I think this goes against the intent of the formatter function (transforming the value in model -> view direction). The View (and the formatter via its directive lives in the View) should only change the model when the change originates from the View. This keeps the model as the source of truth, and if it is set to an invalid value, then so be it - the validity should be reflected in the View, but it should not try to "fix" the model.
With this in mind, let's also use $validators for validation (rather than $parsers/$formatters pipeline):
.directive("iban", function(){
return {
require: "?ngModel",
link: function(scope, element, attrs, ngModel){
if (!ngModel) return;
ngModel.$validators.iban = function(modelValue, viewValue){
// after parser ran, validate the resulting modelValue
return validate(modelValue);
};
function validate(val){
return modelValue === "VALID IBAN"; // for the sake of example
}
}
};
});
$parsers (changing the model value) and $formatters (changing the view value) are called before $validators run.
Another complexity though (and what seems like an Angular's weirdness) is that your capitalize formatter can make the $viewValue to become valid for an invalid $modelValue. This on its own behaves correctly - it formats the $viewValue and keeps the validity as false (since the model is false). However, if you now change the model to the currently-set (and valid) $viewValue, then Angular decides to skip (src) the validators (since it finds no difference between new and old $viewValues), and so the validity never becomes valid despite both the model and view values being valid. Same, for valid-to-invalid case (the invalid low case value never invalidates the model).
This is, however, a rare case, and if coded properly should be avoided altogether. Why? Because the model should rarely (if ever) assume invalid values and should operate within the valid range.
ng-model ensures this (by default, unless you allowInvalid) by setting the model to undefined for invalid values.
So, for your question, decide whether low case IBAN is considered invalid in the ViewModel that you defined:
If low case is invalid, then never assign a low case value to your ViewModel iban property - plunker
If low case is valid, then do case-insensitive iban validator - plunker

Using a variable for ng-required doesn't re-evaluate fields

I have a form where my intent is for required fields to not always be enforced. For example if the user is saving the document as a draft they can enter as little information as they like, if they try and publish the document then they have to enter all the required fields. I'm using a boolean on the controller which changes according to which button has been pressed e.g.
<input type="text" ng-model="field2" ng-required="enforceRequired" />
The problem is that the fields are not re-evaluated when the boolean changes so the form is submitted and then it becomes invalid. Please see this JSFiddle to see what I mean. If you fill in field1 and then click publish it will succeed on the first click and THEN become invalid.
How can I force the validation to run before the form is submitted?
Yarons is right, you are changing the value too late, by late I mean after the form validations has been run. What you can do as a workaround is, after changing the required value, let angular do another cycle and then show your alert. This can be done via $timeout service, although I must mention that it is usually not a good practise to change the flow of your digest actions. It gets pretty messy pretty soon.
Change your publish function like this (and don't forget to inject $timeout)
$scope.publish = function () {
$scope.enforceRequired = true;
$timeout(function () {
if ($scope.form.$valid) {
alert("Published!");
}
});
};
Working fiddle: http://jsfiddle.net/bh9q00Le/14/
The problem is that you are changing the value of enforceRequired in the middle of the digest loop, so the watchers are not re-rendered before you check the input fields' validity (read about digest here).
If you want to get around it, I suggest one of the following methods:
change the value of enforceRequired before you call saveDraft or publish. see example.
call $scope.$apply() after you change the value of enforceRequired. see another example.

how to setup default ng-model value for mutiple switch-toggle inside ng-repeat

I have used switch-toggle inside ng-repeat. I don't know how to set default value to ng-model when you have multiple switch-toggle in your form and on form submit you need to have all the values. I am very much new to angular world and here is the Example In this example on form load the default value for switch-toggle is shown as "OFF". And if I submit form without making any change to the switch-toggle and check in browser console you can see empty model array. And on making some changes then I get the appropriate values.
So, how can I get all the values of the switch-toggle irrespective I make changes or not. As far as my angularJS knowledge is concern I guess it is related to its model. But how to do it in this case I feel I am lost.
This i believe should be model driven. You should intialize your switchModel, something like this
$scope.switchModel = {1:false,2:true,3:false };
instead of {}

Angular - on invalid field, fire method?

When my field becomes invalid, is there a way to fire a method in my js?
So for example, the user fails to fill out the name field, clicks submit, I want to:
console.log('they forgot');
Thanks
There is a $error object made available by AngularJS. This object contains all of the validations on a particular form and tells if they are valid or invalid.
To get access to this property, we can use the following syntax:
formName.inputfieldName.$error
Here is a jsfiddle sample
This document is a good reference for understanding form-validations using AngularJS.
Also, for dealing with custom validations, you can add your own directives. A sample of making such directives is given in the link above.

Resources