Пользовательская дочерняя директива, предоставляющая доступ к родительскому объекту
У меня есть два пользовательских директивы в моем приложении angularJS. Один поступок в качестве родителя и другого действует как ребенок. Я пытаюсь получить доступ к родительской области внутри дочерней директивы. Но я не получаю желаемого результата.
<div ng-controller="CountryCtrl">
{{myName}}
<div ng-controller="StateCtrl">
<state nameofthestate="'Tamilnadu'">
<city nameofthecity="'Chennai'"></city>
</state>
</div>
</div>
и мой script выглядит как
var app = angular.module("sampleApp",[]);
app.controller("CountryCtrl",function($scope){
$scope.myName = "India";
});
app.controller("StateCtrl",function($scope){
});
app.directive("state",function(){return {
restrict : 'E',
transclude: true,
scope : { myName : '=nameofthestate'},
template:"** {{myName}} is inside {{$parent.myName}}<br/><ng-transclude></ng-transclude>"
}});
app.directive("city",function(){return {
restrict : 'E',
require:'^state',
scope : { myName : '=nameofthecity'},
template:"**** {{myName}} is inside {{$parent.myName}} which is in {{$parent.$parent.myName }}<br/> "
}});
Соответствующий JSFiddle доступен в https://jsbin.com/nozuri/edit?html,js,output
Выход, который я получаю,
India
** Tamilnadu is inside India
**** Chennai is inside India which is in Tamilnadu
а ожидаемый результат -
India
** Tamilnadu is inside India
**** Chennai is inside Tamilnadu which is in India
Может ли кто-нибудь просветить меня, что я делаю неправильно здесь?
Ответы
Ответ 1
Директива city $parent является закрытой областью директивы состояния.
Заданная область действия директивы state наследуется для $parent директивы состояния, которая является контроллером, поэтому $parent.MyName = India.
$parent of transcluded scope - это изолированная область действия (scope = {}), поэтому $parent. $parent.MyName = Tamilnadu (часть обновления Angular 1.3)
![enter image description here]()
Немного подробностей о том, что происходит:
Как получить доступ к родительской области из пользовательской директивы * с помощью собственной области * в AngularJS?
transclude: true - директива создает новый "переведённый" ребенок scope, который прототипно наследует от родительской области. Если директива также создает область изоляции, транслированную и изолировать области - братья и сестры. $Parent свойство каждой области ссылается на ту же родительскую область.
Angular v1.3 update: Если директива также создает область выделения, transcluded scope теперь является дочерним объектом изолята. трансляция и выделение областей больше не являются братьями и сестрами. $Parent свойство transcluded scope теперь ссылается на область выделения.
Также ответ Мэтью верен для директивных сообщений родитель-ребенок.
Ответ 2
Это работает для вас? Адаптировано из этого ответа.
Существует нет простого способа доступа к родительскому элементу transcluded content, поэтому мы вводим родительский контроллер в дочерний элемент для доступа к его области.
var app = angular.module('myApp', []);
app.controller("CountryCtrl",function($scope){
$scope.myName = "India";
});
app.controller("StateCtrl",function($scope){
});
app.directive("state",function(){return {
restrict : 'E',
transclude: true,
scope : { myName : '=nameofthestate'},
template:"** {{myName}} is inside {{$parent.myName}}<br/><ng-transclude></ng-transclude>",
controller: function ($scope) {
this.getName = function () {
return $scope.myName;
}
}
}});
app.directive("city",function(){return {
restrict : 'E',
require:'^state',
scope : { myName : '=nameofthecity'},
template:"**** {{myName}} is inside {{parentName}} which is in {{$parent.myName }}<br/> ",
link: function(scope, element, attrs, ctrl) {
scope.parentName = ctrl.getName();
}
}});
Ответ 3
Когда AngularJS сталкивается с переходом, он клонирует HTML до заменив его шаблоном или содержимым templateUrl. Затем, когда встречает ng-transclude, он компилирует переведенный контент, но связывает его с родительской областью, а не с изолированной областью директивы. Таким образом, транслируемый контент по-прежнему имеет доступ к родительский контроллер и его содержимое, в то время как директива HTML имеет изолированная область (или новая область, в зависимости от обстоятельств).
AngularJS Up and Running
Ответ 4
Посмотрите решение моей директивы, оно работает с большим количеством партентов. Я сделал, чтобы удалить transclude и потребовать параметры. Не беспокойтесь о грязном html, просто смотрите js, просто как f..: D
CRM.directive('inputwv', function ($compile) {
var getTemplate = function(contentType) {
var template = '';
switch(contentType) {
case '3':
template = '<input type="number" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px;width:100px">'
break;
case '0':
template = '<input type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
break;
case '1':
template = '<input type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
break;
case '2':
template = '<textarea class="materialize-textarea teal-text" type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
break;
case '4':
template = '<input type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
break;
case '5':
template = '<input type="date" class="datepicker" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px"><script type="text/javascript">$(\'.datepicker\').pickadate({selectMonths: true, selectYears: 15});</script>'
break;
default:
template = '<textarea class="materialize-textarea teal-text" type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
}
return template;
}
var linker = function(scope, element, attrs) {
element.html(getTemplate(attrs.typ)).show();
$compile(element.contents())(scope);
}
return {
restrict: "E",
link: linker
};
});