One should have in mind that:
ng-repeat
, ng-switch
, ng-view
, ng-if
, ng-controller
, ng-include
, etc.This means that when you try to two-way bind some data to a primitive which is inside of a child scope (or vice-versa), things may not work as expected. Here's an example of how easily is to "break" AngularJS.
This issue can easily be avoided following these steps:
controllerAs
syntax as it promotes the use of binding to a "dotted" objectscope
variables rather than child scope. like inside ng-if
we can use ng-model="$parent.foo"
..An alternative for the above is to bind ngModel
to a getter/setter function that will update the cached version of the model when called with arguments, or return it when called without arguments.
In order to use a getter/setter function, you need to add ng-model-options="{ getterSetter: true }"
to the element with the ngModal
attribute, and to call the getter function if you want to display its value in expression (Working example).
View:
<div ng-app="myApp" ng-controller="MainCtrl">
<input type="text" ng-model="foo" ng-model-options="{ getterSetter: true }">
<div ng-if="truthyValue">
<!-- I'm a child scope (inside ng-if), but i'm synced with changes from the outside scope -->
<input type="text" ng-model="foo">
</div>
<div>$scope.foo: {{ foo() }}</div>
</div>
Controller:
angular.module('myApp', []).controller('MainCtrl', ['$scope', function($scope) {
$scope.truthyValue = true;
var _foo = 'hello'; // this will be used to cache/represent the value of the 'foo' model
$scope.foo = function(val) {
// the function return the the internal '_foo' varibale when called with zero arguments,
// and update the internal `_foo` when called with an argument
return arguments.length ? (_foo = val) : _foo;
};
}]);
Best Practice: It's best to keep getters fast because Angular is likely to call them more frequently than other parts of your code (reference).