25

I'm trying to write a directive which make use of isolated scope and ngModel directive.

Problem:
When the model is updated in the directive the value of the caller is not getting updated.

HTML:

<test-ng-model ng-model="model" name="myel"></test-ng-model> 

Directive:

app.directive( 'testNgModel', [ '$timeout', '$log', function ($timeout, $log) { function link($scope, $element, attrs, ctrl) { var counter1 = 0, counter2 = 0; ctrl.$render = function () { $element.find('.result').text(JSON.stringify(ctrl.$viewValue)) } $element.find('.one').click(function () { if ($scope.$$phase) return; $scope.$apply(function () { var form = angular.isObject(ctrl.$viewValue) ? ctrl.$viewValue : {}; form.counter1 = ++counter1; ctrl.$setViewValue(form); }); }); $element.find('.two').click(function () { if ($scope.$$phase) return; $scope.$apply(function () { var form = angular.isObject(ctrl.$viewValue) ? ctrl.$viewValue : {}; form.counter2 = ++counter2; ctrl.$setViewValue(form); }); }); $scope.$watch(attrs.ngModel, function (current, old) { ctrl.$render() }, true) } return { require: 'ngModel', restrict: 'E', link: link, //if isolated scope is not set it is working fine scope: true, template: '<div><input type="button" class="one" value="One"/><input type="button" class="two" value="Two"/><span class="result"></span></div>', replace: true }; }]); 

Demo: Fiddle

If the isolated scope is not set it works fine: fiddle

3
  • 1
    scope: true does not create an isolate scope, it creates a new child scope that prototypically inherits from the parent scope, hence the reason $parent.model works. (An isolate scope is created when we use the scope: { ... } syntax. Here, an new child scope is also created, but it does not prototypically inherit from the parent.) In general, a child scope should be used with ng-model since you are creating a component that needs to interact with other directives (i.e., ng-model). So I suggest you go with your second, working, fiddle. Commented Aug 31, 2013 at 15:26
  • @MarkRajcok that is not an option for me since the directive is more complex and it adds some custom attributes to the scope which will lead to pollution of the parent scope Commented Aug 31, 2013 at 15:32
  • Ok, use scope: true, but also use an object, not a primitive: <test-ng-model ng-model="someObj.model" ...>. fiddle. Commented Aug 31, 2013 at 15:38

2 Answers 2

13

As discussed in the comments, it is generally not recommended to use a child scope (scope: true or scope: { ... }) with ng-model. However, since Arun needs to create additional scope properties, scope: true can be used with an object, not a primitive. This leverages prototypical inheritance, so $parent is not neeed:

<test-ng-model ng-model="someObj.model" ...> 

fiddle

Sign up to request clarification or add additional context in comments.

2 Comments

is it possible to make it work with isolated scope instead of new scope jsfiddle.net/arunpjohny/gbfNY/1
@ArunPJohny, the parent scope is not getting updated -- notice that the {{someObj.model | json}} output is empty. For more about how isolate scopes and ng-model don't mix, see stackoverflow.com/questions/11896732/….
7

Because you created an isolated scope, ngModel="model" refers to your new isolated scope. If you want to refer to your AppController scope, you should use $parent:

<test-ng-model ng-model="$parent.model" name="myel"></test-ng-model> 

2 Comments

scope: true doesn't create an isolate scope.
Good point. My solution would work anyway, even if the scope is not isolate. But the solution you propose is far better.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.