AngularJS: включенная директива и доступ к модели

Я создаю директиву smart input, которая будет обертывать элемент ввода текста, и ей требуется доступ к модели элемента ввода, чтобы манипулировать некоторыми классами в директиве.

Поскольку элемент ввода может быть одним из многих типов (текст, электронная почта, пароль), мне нужно включить директиву и иметь возможность добавлять различные типы проверки для каждого из них.

Проблема, с которой я сталкиваюсь (как и со многими другими в Интернете), заключается в наследовании области видимости.

Вот как выглядит мой текущий код
HTML

<smart-input ng-model="username">
  <span ng-show="isTyping">{{ placeholder }}</span>
  <input type="text" name="username" ng-model="username" ng-minlength="4" ng-maxlength="20" required />
</smart-input>

JS

angular.module('myApp').directive('smartInput', function ($compile) {
  return {
    restrict: 'E',
    transclude: true,
    replace: true,
    scope: {
      model: '=ngModel'
    },
    template: '<div class="text-input" ng-class="{typing: isTyping}" ng-transclude>' +
              '</div>',
    link: function(scope, element, attrs) {
      scope.isTyping = false;

      scope.$watch('model', function(value) {
        console.log(value);
        scope.isTyping = value.length > 0;
      });
    }
  };
});

По сути, value внутри функции $watch не определено, поэтому, очевидно, я делаю это неправильно.

Итак, как я могу привязать модель к полю ввода, в то время как директива имеет ссылку на тот же объект и может watch его значение?


person Marko    schedule 03.02.2014    source источник
comment
Можете ли вы создать jsfiddle или plunkr со своим кодом?   -  person Michał Miszczyszyn    schedule 03.02.2014
comment
это работает plnkr.co/edit/pYfiafbQR6JOZhDEQGQS?p=preview   -  person Khanh TO    schedule 03.02.2014
comment
Интерпретируя текст вопроса, я предполагаю, что вам нужно что-то вроде этого: ng-model="$$prevSibling.model" plnkr.co/edit/DjQibwb5cmIVIFJzcEie ?p=preview, но без $$prevSibling, правильно?   -  person Khanh TO    schedule 03.02.2014
comment
@KhanhTO это точно. Я не хочу указывать $$prevSibling.model, а делаю это автоматически. Это связано с тем, что другие разработчики будут использовать эту директиву, и я хотел бы сделать ее максимально простой в использовании.   -  person Marko    schedule 03.02.2014


Ответы (1)


Когда вы используете изолировать область с включением, ваши области не имеют отношений родитель/потомок. Это выглядит так:

<controllerScope>
     <smartInputScope>
     <transcludedContentScope>

Вот почему, чтобы получить доступ к свойству model smartInputScope, нам нужно получить доступ к $$prevSibling.model. В вашем первом примере ng-model="username" работает, потому что эта область наследуется от controllerScope, она обращается к свойству области родителя.

Ознакомьтесь с моим решением с пользовательским включением: http://plnkr.co/edit/cV9urKJdcn4mKlpqPJTr?p=preview

app.directive('smartInput', function($compile) {
  return {
    restrict: 'E',
    transclude: true,
    replace: true,
    scope: {
      model: '=ngModel'
    },
    template: '<div class="text-input" ng-class="{typing: isTyping}">' +
      '</div>',
    compile: function(element, attr, linker) {
      return {
        pre: function(scope, element, attr) {
          linker(scope, function(clone) { //bind the scope your self
            element.append(clone); // add to DOM
          });
        },
        post: function postLink(scope, iElement, iAttrs) {
          scope.isTyping = false;

          scope.$watch('model', function(value) {
            console.log(value);
            scope.isTyping = value.length > 0;
          });
        }
      };
    }
  };
});

В html мне больше не нужно $$prevSibling:

<input type="text" name="username" ng-model="model" ng-minlength="4" ng-maxlength="20" required />
person Khanh TO    schedule 04.02.2014