Jonathan
Jonathan

Reputation: 4918

$ViewValue is not being used when Element type directive

I created this simple directive that uses a formatter and it is not updating the input when the directive is used as an element or when it is an attribute of a div.

JSBIN: http://jsbin.com/rifaxuvihu/edit?html,js,output

    angular.module('myApp', [])

    .controller('myCtrl', function($scope) {

  $scope.foo = '123';
  console.log('------ MODEL CHANGED ($scope.foo = "123") ------');

  $scope.changeModel = function() {
    $scope.foo = 'abc';
    console.log('------ MODEL CHANGED ($scope.foo = "abc") ------');
  };

})

.directive('myDirective', function() {
  return {
                restrict: 'AE',
                transclude: true,
                require: 'ngModel',
                template: function($element, $attrs, $ctrls) {
                    var inp, lbl = 'label'; 

                    if ($attrs.type == 'html'){
                        inp = [
                            '<summernote class="form-control" ng-model="ngModel" ',
                            '   name="{{name}}" placeholder={{placeholder}} height="{{height}}"></summernote>'
                        ];
                        lbl = 'div';
                    } else
                        inp = [
                            '<input class="form-control" ng-model="ngModel" ',
                            '   type="{{type}}" />'
                        ];

                    var ret = [
                        '<div class="advform-input form-group inp-{{type}} {{cols}}">',
                        '   <' + lbl + ' class="advform-lbl">',
                        inp.join('\n'),
                        '       <div class="helper" ng-if="type != \'html\'">{{ placeholder }}</div>',
                        '       <div class="desc">{{ desc }}</div>',
                        '   </' + lbl + '>',
                        '</div>'
                    ].join('\n');

                    return ret;
                },
                scope: {
                    placeholder: '@',
                    ngModel: '=?',
                    type: '@',
                    name: '@',
                    height: '@'
                },
                link: function ($scope, $element, $attrs, $ngModel) {
                    console.log('ooi');
                    if (true){

                        $ngModel.$formatters.unshift(function(modelVal) {
                            console.log('-- Formatter --', JSON.stringify({
                              modelVal:modelVal,
                              ngModel: {
                                viewVal: $ngModel.$viewValue,
                                modelVal: $ngModel.$modelValue
                              }
                            }, null, 2));
                            return 1 + '-) ' +modelVal;
                          });

                          // same as $watch('foo')
                          $scope.$watch(function() {
                            return $ngModel.$viewValue;
                          }, function(newVal) {
                            console.log('-- $watch "foo" --', JSON.stringify({
                              newVal:newVal,
                              ngModel: {
                                viewVal: $ngModel.$viewValue,
                                modelVal: $ngModel.$modelValue
                              }
                            }, null, 2));
                          });
                    }
                }
  };
})

;

the html:

<!DOCTYPE html>

<html ng-app="myApp" ng-controller="myCtrl">

<head>

  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.18/angular.min.js"></script>

</head>

<body>
<form name="form">
  <my-directive type="text" name="foo" ng-model="foo"></my-directive>
  <input my-directive type="text" name="foo" ng-model="foo" />
  <div my-directive type="text" name="foo" ng-model="foo"></div>
</form>
<button ng-click="changeModel()">Change Model</button>
  <p>$scope.foo = {{foo}}</p>
  <p>Valid: {{!form.foo.$error.test}}</p>
</body>

</html>

Upvotes: 0

Views: 146

Answers (1)

Jonathan
Jonathan

Reputation: 4918

The problem is that the directive creates a new scope and the viewValue of the ngModel of the directive is different from the one created within the template.
To fix it, you can change the ng-model of the template to $parent.ngModel.
So the format will work as expected.

Upvotes: 1

Related Questions