Playing with Scope Inheritance In Angular

In my previous blog I have discussed about the prototypical inheritance in Javascript, In AngularJS, a child scope normally prototypical inherits from its parent scope.Today while working with angular I found a interesting concept regarding prototypical inheritance in angular. Now lets directly start with an example,

Here is the PLUNK.

In the above example We have created an array “Skills” which contains a set of skills, and a model “mySkill” to store a particular skill in $scope. We are using the “Skills” array to populate our check boxes and ‘mySkill’ model to store the skill selected by the user.Finally we are showing the skill selected by the user. But this will not work the way we are  expecting.

It will not update our model ‘mySkill’ according to the checkbox selected by the user. This looks like a strange issue. Now the question is why Its not updating our model properly? This is because ng-repeat creates a new child scope which is prototypically inherited from parent scope and the child scope gets its own property(‘mySkill’) that hides/shadows the parent property of the same name, But does not update the parent scope ‘mySkill’ property. This is not something AngularJS is doing – this is how JavaScript prototypical inheritance works.  Directives like ng-repeat, ng-view and ng-include create new child scope where this kind of problem occurs.

This issue with primitives can be easily avoided by following the best practice of always have a ‘.’ in ng-models.Having a ‘.’ in models will ensure that prototypical inheritance is in play. So, we should use

<input type="text" ng-model="someObj.prop1"> rather than 
<input type="text" ng-model="prop1">.

If you really want/need to use a primitive, then we can use $parent.parentScopeProperty in the child scope which will prevent the child scope from creating its own scope.

<input type="text" ng-model="$parent.prop1">

Now to make our example work properly we can modify it as below,

Here is the PLUNK.

So what exactly we did is we have modified  $scope.mySkill = “Java” to $scope.mySkill = {fav: “Java”} and used mySkill.fav as our model. So now inside ng-repeat It will not create a duplicate mySkill property in the child scope instead it will update the parent scope mySkill.fav property and everything will work as expected.

This is one of the “Best Practices” in Angular JS.

Summary:

If we use a primitive type (as ‘mySkill’ in 1st example) as model for data binding, essentially ng-repeat will create a new child scope property with the same name . Changing the child scope property’s value (i.e., using ng-model, hence child scope property mySkill) does not change the  parent scope mySkill property. So in my first example above, each child scope gets a mySkill property that is independent of the mySkill property defined in the controller or the parent scope. But if we will use a Object type , It will use prototypical inheritance and always update the property on the parent scope.