ngModel нуждается в $parent, когда находится в Transcluded html

У меня есть директива для поля ввода, которое использует трансклюзию, чтобы взять элементы, заключенные в элементе директив, который включает атрибут ng-model. После прочтения бесчисленных вопросов SO и документации Angular, чтобы узнать, как заставить ng-model в включенном html синхронизироваться с ng-model в моей директиве, я, наконец, наткнулся на трюк, чтобы заставить его работать. То есть использовать $parent, где ng-model находится в поле ввода. Это все прекрасно и модно, однако кажется неуклюжим/хакерским.

Здесь показан плункер: http://plnkr.co/edit/gEje6Z2uuTs9DFPeCZfv

Я попытался сделать это немного более элегантным, повозившись с функцией включения в моей функции ссылки, например так:

```

      var transcludedContent, transclusionScope;

      transcludeFn(scope, function(clone, scope) {
        //headerCtrl.$element.append(clone);
        transcludedContent = clone;
        transclusionScope = scope;

        console.log('scope form: ', scope);
        console.log('transclude form: ', clone);


      });

```

Также показано в этом планкере: http://plnkr.co/edit/11k9LiA5hyi4xydWBo3H?p=preview< /а>

Можно было бы подумать, что функция включения позволит вам перезаписать область включения областью действия вашей директивы, тогда атрибуты ng-model будут связаны и привязаны к области действия директивы, однако это не так.

Хотя $parent.<ng-model> действительно работает, это кажется очень хакерским и может привести к ошибкам, например, если моя директива не использовалась с родительской областью, в которой не определен объект account.


person britztopher    schedule 17.03.2015    source источник


Ответы (1)


Есть несколько способов сделать это.

1) Разоблачение переменной account с помощью =

http://plnkr.co/edit/DxsipWRj0AJe6Yi3bhse

JS:

app.directive('formControl', [function(){
    return {
      restrict: 'EA',
      template: '<div ng-transclude></div>{{account.name}}',
      scope: {
        account: '='
      },
      transclude: true,
      link: function(scope, element, attrs){
        scope.account={};

        console.log('SCOPE: ', scope)
      }
    };
}]);

HTML:

<form-control account='account'>
  <label for="name">Enter Name:</label>
  <input name="name" ng-model="account.name" \>
</form-control>

2) Используя функцию transclude:

Это похоже на то, что делают ngIf и ngRepeat. ngRepeat на самом деле украшает каждую область $index и подобными значениями, точно так же, как вы хотите украсить свою область account.

http://plnkr.co/edit/cZjWqIgO23nzc0kMZA57

JS:

app.directive('formControl', ['$animate', function($animate){
    return {
      restrict: 'EA',
      transclude: 'element',
      link: function(scope, element, attrs, ctrl, transclude){
        //this creates a new scope that inherits from the parent scope
        //that new scope will be what you'll be working with inside your
        //transcluded html
        transclude(function (clone, scope) {
          scope.account = {name:'foobar'};
          $animate.enter(clone, null, element);

          console.log('SCOPE: ', scope)
        });
      }
    };
}]);

HTML:

<form-control>
  <label for="name">Enter Name:</label>
  <input name="name" ng-model="account.name" \><br>
  {{account.name}}
</form-control>
person jlowcs    schedule 17.03.2015
comment
Большое спасибо за подробное объяснение. Интересно, почему вы не можете использовать изолированную область, а затем назначить эту область для функции включения. Можно было бы подумать, что ng-model=account, первоначально определенный в html и назначенный родительской области, затем будет назначен изолированной области действия директивы. Это может быть полезно, когда вы хотите полностью использовать brand new нетронутую область. - person britztopher; 18.03.2015
comment
Вы можете позвонить transclude(scope.$new(true), function (...) {...}) - person jlowcs; 18.03.2015