AngularJS - доступ к родительским директивным свойствам из дочерних директив

Это не должно быть слишком сложно, но я не могу понять, как это сделать.

У меня есть родительская директива, например:

directive('editableFieldset', function () {
  return {
    restrict: 'E',
    scope: {
      model: '='
    },
    replace: true,
    transclude: true,

    template: '
      <div class="editable-fieldset" ng-click="edit()">
        <div ng-transclude></div>

        ...

      </div>',

    controller: ['$scope', function ($scope) {
      $scope.edit = ->
        $scope.editing = true

       // ...
    ]
  };
});

И дочерняя директива:

.directive('editableString', function () {
  return {
    restrict: 'E',
    replace: true,

    template: function (element, attrs) {
      '<div>
        <label>' + attrs.label + '</label>
        <p>{{ model.' + attrs.field + ' }}</p>

        ...
      </div>'
    },
    require: '^editableFieldset'
  };
});

Как я могу легко получить доступ к свойствам model и editing родительской директивы из дочерней директивы? В моей функции ссылок у меня есть доступ к родительской области - следует ли использовать $watch для просмотра этих свойств?

Соединяясь, я бы хотел:

<editable-fieldset model="myModel">
  <editable-string label="Some Property" field="property"></editable-string>
  <editable-string label="Some Property" field="property"></editable-string>
</editable-fieldset>

Идея состоит в том, чтобы по умолчанию отображался набор полей. Если нажать, они станут входами и могут быть отредактированы.

Ответ 1

Взяв вдохновение из этого сообщения SO, у меня есть рабочее решение здесь, в этом plunker.

Мне пришлось немного поменяться. Я также выбрал изолированную область на editableString, потому что было легче связать правильные значения с шаблоном. В противном случае вам придется использовать compile или другой метод (например, $transclude service).

Вот результат:

JS:

var myApp = angular.module('myApp', []);

myApp.controller('Ctrl', function($scope) {

  $scope.myModel = { property1: 'hello1', property2: 'hello2' }

});


myApp.directive('editableFieldset', function () {
  return {
    restrict: 'E',
    scope: {
      model: '='
    },
    transclude: true,
    replace: true,
    template: '<div class="editable-fieldset" ng-click="edit()"><div ng-transclude></div></div>',
    link: function(scope, element) {
      scope.edit = function() {

        scope.editing = true;
      }
    },
    controller: ['$scope', function($scope) {

      this.getModel = function() {
        return $scope.model;
      }

    }]
  };
});

myApp.directive('editableString', function () {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      label: '@',
      field: '@'
    },
    template: '<div><label>{{ label }}</label><p>{{ model[field] }}</p></div>',
    require: '^editableFieldset',
    link: function(scope, element, attrs, ctrl) {

      scope.model = ctrl.getModel();
    }
  };
});

HTML:

  <body ng-controller="Ctrl">
    <h1>Hello Plunker!</h1>
    <editable-fieldset model="myModel">
      <editable-string label="Some Property1:" field="property1"></editable-string>
      <editable-string label="Some Property2:" field="property2"></editable-string>
    </editable-fieldset>
  </body>

Ответ 2

Вы можете получить доступ к родительскому контроллеру, передав атрибут в дочерней директивной ссылке

link: function (scope, element, attrs, parentCtrl) {
    parentCtrl.$scope.editing = true;
}