AngularJS fire change event when model updated programmatically - angularjs

The fact that ng-change is only for user input, and does not fire when changes are made to the model programmatically, is really causing me a headache today. I'm working with a user input form which has the separate parts of a name, as well as dynamically built and ordered credentials. The form has a "displayName" field that gets updated when the name parts are changed. This is encapsulated in a directive which I need to use in a larger view. Here's where things get hairy. I need to hide the name part fields in my directive and use the outer form's name fields. I thought this would be easy by wiring up a function to update the hidden text input fields, and thus my displayName field. Then I found out programmatic changes to the model do not fire the change event.
I tried creating a watch for one of the name fields to see if I could get it to update the displayName field, but no luck.
this.scope.$watch('provider.firstName', function (event) {
namePropertyChanged2(displayNameOverridden, displayName, provider, credentials);
});
When I change the input field for firstName, it modifies the directive's value 'provider.firstName', and runs the 'namePropertyChanged2' function. The code listed runs in an initialize function, where 'displayName' is a local variable assigned from this.scope.provider.displayName. The watch assignment required me to make local variables instead of passing in controller variables. Not sure why, but whatever. So this function runs and 'displayName' is updated with the correct value... and the input field it's bound to is not updated. Bummer.
What would be ideal is to manually trigger the change event when the model changes, which would update the displayName and much rejoicing to be had.

Related

Why does binding trigger a $watch although no data was changed?

I have an entity in the scope that is being edited by the user. Each time it gets modified, I want to trigger some custom validation. So I have:
// validate the position if anything has changed
$scope.$watch("entity", function() {
if ($scope.entity.Id) {
$scope.validate();
}
}, true /* watch "by value" (see: https://docs.angularjs.org/guide/scope#scope-life-cycle) */);
So far so good. Now, since this is a big entity with quite some fields, not all of the fields participate initially in data-binding. Only portions of the fields are visible to the user by using a tab control. When the user switches tabs, another portion of the entity is shown.
However, when the additional controls get bound to the corresponding fields of the entity, the $watch gets triggered even though the binding doesn't change any value on the entity.
Why is this the case and how could I prevent it?
Note:
I thought that the data-binding is possibly adding some internal $... fields to entity but these are hopefully disregarded (at least this is the case in angular.equals so they should probably be disregarded in the $watch too, I assume).
$watch with object equality flag true compares the properties of the old object copy with the current object. Therefore the listener fires when a property name is changed, added, or removed. You can try something like the following:
$scope.$watch("entity", function(newVal, oldVal) {
if(Object.keys(newVal).length !== Object.keys(oldVal).length)
return; //Detect added properties
if ($scope.entity.Id) {
$scope.validate();
}
}, true

Get all forms from $scope

Is it possible to get all the forms from the $scope and set them to prestine?
Up to now I have been setting the prestine state using the form name, e.g.
$scope.coachingSessionFrm.$setPristine()
the setPrestine() method removes the dirty flag so that the state of the form elements are now considered clean right? Only after a change after prestine will they be dirty?

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 {}

Revalidate field with custom directive in AngularJS

I have this scenario where a field is invalid due to another selection on the form. When that selection changes I want to revalidate. I tried calling $setViewValue on the field when the selection changes, but that doesn't refire the validation. Any ideas?
I have a hack working, but I would prefer a clean solution.
I ran into the same issue and found a workaround/feature that appears to be undocumented. If you need to trigger ngModelController to revalidate, you can either do:
ngModelCtrl.$setViewValue(value, 'your event name', true);
or if you don't need to update your model value
ngModelCtrl.$commitViewValue(true);
The true in both cases above is a flag for revalidation. Without this flag, the issue I was running into was that if the model value does not change, then angular simply skips the validation. I am using this way to manually mark a custom control as $dirty
Source:
https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js#L1843
Write a directive, say validation, and place it on your field in the definition of this directive in the:
link:function(scope,element,args){
element.bind('onfocus',function(){
// Your logic
})
// Similarly, bind other relevant events like key presses, etc.
}
Put a ng-change on your select and broadcast an event in it:
$rootScope.$broadcast("selectChangedEvent");
Then, in a directive you have placed on your field, simply put in the link function:
$rootScope.$on("selectChangedEvent", () => ngModelCtrl.$validate());
$validate runs each of the registered validators of your field.

How to watch for changes to a object in AngularJS from a controller?

Assuming I have an object in the rootScope:
$scope.mydict = {
'apple': {'properties':{'color':'red', 'texture': 'mm'}, 'physics': {'bouncy': 'no', 'impact': 'breaks'}},
'pear': {'properties':{'color':'red', 'texture': 'mm'}, 'physics': {'bouncy': 'no', 'impact': 'breaks'}}
}
Assuming depending on how the user interacts, this $scope may have more and more fruits indicated by the key. How would I be able to $watch for changes to the dictionary for any new items that are added and process them?
I tried:
$watch("mydict" ...)
Though it complains about mydict not being there and doesnt seem to allow me to watch dictionaries. Note that the $scope.mydict is initialized by another service i defined to get the resource from to populate that variable in the $scope, so it might not exist in the directive that is responsible for $watch-ing the data changing.
What I want to do is for every new fruit that gets added to "mydict", output the "properties.texture" of ONLY that item. If it is possible to watch and see if any new frutis added even have a "properties.texture" before doing anything(i.e. alert), that would be even better. Though I am not sure if this is possible.

Resources