Можно ли использовать $$prevSibling для доступа к данным области в директиве "transcluded"?

моя настройка директивы выглядит следующим образом:

<div data-directive-a data-value="#33ff33" data-checked="true">
  <div data-directive-b></div>
</div>
  • я использую transclusion для обеспечения directiveB отрисовывается.
  • directiveA имеет флажок, который предназначен для изменения некоторого значения всякий раз, когда он установлен.
  • это значение должно быть доступно в directiveA и directiveB's область.

мне удалось это сделать, но только путем ссылки $$prevSibling - есть ли лучший способ?

вот код: http://jsfiddle.net/janeklb/yugQf/ (в этом примере нажатие флажка просто означает "очистить" значение)

--

немного больше глубины: "Содержание"directiveA (то, что трансцендируется в него) не всегда directiveB. Другое directiveB-подобные директивы также окажутся там. The directiveB "типы" всегда будут использоваться в directiveA.

2 ответов


чтобы избежать слишком большого соединения ваших компонентов, я бы избегал использования $$prevSibling. Лучшее решение с вашего directiveB-ожидается, что подобные компоненты будут использоваться в directiveA компоненты-использовать require.

.directive( 'directiveB', function () {
  return {
    require: '^directiveA',
    scope: true,
    link: function ( scope, element, attrs, directiveA ) {
      scope.obj = directiveA.getObj();
    }
  };
})

на ^require указывает, что где-то на элементе этой директивы или на любом элементе над ней в иерархии DOM есть директива под названием directiveA, и мы хотим вызвать методы на своем контроллере.

.directive( 'directiveA', function () {
  return {
    // ...
    controller: function ( $scope ) {
      // ...
      this.getObj = function () {
        return $scope.obj;
      };
    }
  };
})

так что теперь в directiveB вы может использовать ng-model="obj.attr".

есть много вариантов этого, но, учитывая, насколько общим был вопрос, я считаю, что это лучший подход. Вот обновленная Скрипка:http://jsfiddle.net/yugQf/7/.


@Josh упомянул в своем ответе, что

лучшее решение с вашего directiveB-ожидается, что подобные компоненты будут использоваться в directiveA компоненты-использовать require.

я играл с этим, и я считаю, что контроллер на directiveA - это только решение (так +1 Джош). Вот как выглядят области, использующие скрипку OP: scopes picture

(обратная коричневая стрелка и у вас есть $$previousSibling вместо $$ / / сделать.)

кроме $$previousSibling, область 004 не имеет пути для изоляции области 003. Обратите внимание, что объем 004-это раскрываемый область,directiveA создает, и с directiveB не создает новую область, эта область также используется directiveB.

так как объект, который вы хотите поделиться с directiveB создано в directiveAконтроллер, мы также не можем использовать атрибуты для обмена данными между директивами.


создание модели внутри a директива, а затем делиться этой моделью с внешним миром довольно нетипично. Как правило, вы хотите определить свои модели вне ваших директив и даже вне ваших контроллеров (послушайте несколько минут Misko). Услуги часто являются хорошим местом для хранения ваших моделей/данных. Контроллеры обычно должны ссылаться на части модели(моделей), которые необходимо спроецировать в представление, с которым они связаны.

для простоты, я собираюсь определить модель на контроллере директивы будут обращаться к этой модели обычным способом. В педагогических целях,directiveA по-прежнему будет использовать область изолирования и directiveB создаст новую дочернюю область с помощью scope: new как в ответе @Josh. Но любой тип (изолировать, новый ребенок, без новой области) и комбинация будут работать, теперь, когда у нас есть модель, определенная в родителе масштаб.

Ctrl:

$scope.model = {value: '#33ff33', checkedState = true};

HTML-код:

<div ng-controller="NoTouchPrevSibling">
   <div data-directive-a data-value="model.value" data-checked="model.checkedState">
      <div data-directive-b></div>
   </div>

по другим педагогическим причинам я решил передать directiveA два свойства модели как отдельные атрибуты, но вся модель/объект также могли быть переданы. Поскольку directiveB создаст дочернюю область, ему не нужно передавать какие-либо атрибуты, поскольку он имеет доступ ко всей области родителя / контроллера свойства.

директивы:

app.directive('directiveA', function () {
    return {
        template: '<div>' 
            + 'inside parent directive: {{checkedState}}'
            + '<input type="checkbox" ng-model="checkedState" />'
            + '<div ng-transclude></div>'
            + '</div>',
        transclude: true,
        replace: true,
        scope: {
              value: '=',
              checkedState: '=checked'
            },
    };
});
app.directive('directiveB', function () {
    return {
        template: '<div>' 
            + '<span>inside transcluded directive: {{model.checkedState}}</span>'
            + '<input type="text" ng-model="model.value" />'
            + '</div>',
        replace: true,
        scope: true
    };
});

области:

scopes

обратите внимание, что дочерняя область directiveB (006) наследуется от области трансклюзии directiveA (005).

после нажатия флажка и изменения значения в текстовом поле:

scopes after interaction

обратите внимание, что угловые ручки обновляют свойства области изоляции. Нормальный прототип JavaScript наследство предоставляет дочерней области directiveB доступ к model в области контроллера (003).

Скрипка