Directive with isolated scope and ng-model

18,244

Solution 1

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

Solution 2

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>
Share:
18,244

Related videos on Youtube

Arun P Johny
Author by

Arun P Johny

LinkedIn

Updated on June 21, 2022

Comments

  • Arun P Johny
    Arun P Johny about 2 years

    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

    • Mark Rajcok
      Mark Rajcok almost 11 years
      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.
    • Arun P Johny
      Arun P Johny almost 11 years
      @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
    • Mark Rajcok
      Mark Rajcok almost 11 years
      Ok, use scope: true, but also use an object, not a primitive: <test-ng-model ng-model="someObj.model" ...>. fiddle.
  • Mark Rajcok
    Mark Rajcok almost 11 years
    scope: true doesn't create an isolate scope.
  • Wagner Francisco
    Wagner Francisco almost 11 years
    Good point. My solution would work anyway, even if the scope is not isolate. But the solution you propose is far better.
  • Arun P Johny
    Arun P Johny almost 11 years
    is it possible to make it work with isolated scope instead of new scope jsfiddle.net/arunpjohny/gbfNY/1
  • Mark Rajcok
    Mark Rajcok almost 11 years
    @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/….