Как передать аргумент директиве без чрезмерной записи родительской области?
Мне нужно создать директиву, действующую на ячейки таблицы, где строки таблицы отображаются с помощью ng-repeat
- с этой целью я частично полагался на этот ответ на вопрос "Вызов функции, когда ng-repeat завершен". В отличие от этого Q & A, мне нужно передать аргумент моей директиве, и для этого я частично воспользовался этим ответом (к вопросу под названием "Angularjs - передать аргумент директиве" ).
Итак, в моем случае я добавил fixed-column-tooltip
для моей директивы и columnselector
в качестве аргумента для <tr>
следующим образом:
<tr fixed-column-tooltip columnselector=".td-keyField" ng-repeat="trData in trDataWatch">
Но когда на второй ответ я добавил, что то, что я узнал, является "областью выделения" моей директивы, я больше не имел доступа к исходной области, необходимой в соответствии с первым ответом:
'use strict';
angular.module('cmt.cases.directives')
.directive('fixedColumnTooltip', function ($timeout) {
return {
restrict: 'A',
scope: {
columnselector: '@'
},
link: function (scope, element, attr) {
if (scope.$last === true) { //undefined because not operating on original scope
...
Есть ли способ сохранить доступ к исходной области, но также иметь доступ к аргументу columnselector
?
Ответы
Ответ 1
Несмотря на то, что я почти полностью новичок в Angular, я отвечаю на свой вопрос, но все еще хочу получить дополнительные ответы, если я решил свою проблему, не считается "идиоматическим" Angular.
В частности, вместо использования области выделения я использовал третий аргумент link/function attrs
(attributes) в моем коде ниже, чтобы в противном случае получить новый атрибут columnselector
в html вместе с моей директивой. Это общепринятая практика?
'use strict';
angular.module('cmt.cases.directives')
.directive('fixedColumnTooltip', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
if (scope.$last === true) {
$timeout(function () {
element.parent().find(attrs.columnselector).each(function() {
var td = $(this);
var span = td.find('span');
if (span.width() > td.width()){
span.attr('data-toggle','tooltip');
span.attr('data-placement','right');
span.attr('title', span.html());
}
});
});
}
}
}
});
ДОПОЛНЕНИЕ:
Как вы можете видеть из комментариев, мне не удалось получить код из этого ответа, чтобы работать, несмотря на то, что вы пытаетесь это сделать несколькими разными способами. Если я делаю что-то неправильно в отношении включения этого ответа, пожалуйста, дайте мне знать.
Тем временем я нашел другой способ сделать это, но это почти наверняка больше "запаха кода", чем использование аргумента attrs
. В частности, я обнаружил, что могу использовать область изоляции, а затем получить доступ к этому атрибуту scope $parent
. Тогда я бы начал свой код следующим образом, но я не сторонник этого, но я просто отмечаю это, поскольку кажется, что TMTOWTDI (там более одного способа сделать это), безусловно, относится к Angular:
'use strict';
angular.module('cmt.cases.directives')
.directive('fixedColumnTooltip', function ($timeout) {
return {
restrict: 'A',
scope: {
columnselector: '@'
},
link: function (scope, element, attrs) {
if (scope.$parent.$last === true) {
$timeout(function () {
element.parent().find(scope.columnselector).each(function() {
...
Ответ 2
Вы можете использовать
'use strict';
angular.module('cmt.cases.directives')
.directive('fixedColumnTooltip', function ($timeout) {
return {
restrict: 'A',
scope: {
columnselector: '@',
$last: '=$last',
},
link: function (scope, element, attr) {
if (scope.$last === true) {
....
второй параметр для области будет передавать $последний параметр по ссылке.
EDIT:
Так как $last доступен только в области повторного элемента, вы можете получить его из области видимости элемента, например
'use strict';
angular.module('cmt.cases.directives')
.directive('fixedColumnTooltip', function ($timeout) {
return {
srestrict: 'A',
scope: {
columnselector: '@',
},
link: function (scope, element, attrs) {
var elemScope = element.scope();
if (elemScope.$last){
......
}
}
}
Ответ 3
Хорошо, прежде всего, потому, что вы используете область изоляции, не означает, что вы не можете получить доступ к чему-либо в родительской области. Область изоляции предназначена для ограничения того, что вы получаете по умолчанию, но вы можете указать, что хотите от родительской области. Правильный способ сделать это - установить двустороннюю привязку в вашей директиве, используя "parentScopeVariable:" = '". Простите ужасное форматирование, я нахожусь на мобильном телефоне, и я хочу ложиться спать:-).
Итак, как вы сказали, вы тоже можете использовать параметр "attrs". Есть даже сложные методы $eval по настройке объектов в родительском пространстве, которые передаются только как attrs. В любом случае вы не можете иметь более одной директивы с областью выделения для данного элемента/компонента, поэтому вам действительно нужно быть осторожным при использовании области выделения. Это определенно поддается чистому дизайну, потому что вы должны быть преднамеренными в отношении того, что вы используете в своей директиве. Точка, полагающаяся на attrs, является прекрасной и необходимой иногда, на мой взгляд. По общему признанию, он чувствует себя немного взломанным или каким-либо другим (думая о запахе кода), но я не думаю, что для этого есть веский аргумент.
Наконец, я потратил много времени на сайт документа Angular API doc, и там было много хороших вещей. Там довольно хорошая директивная ссылка на странице компиляции $compile. Опять же, мобильный, извините. Если бы я был на полном компьютере, я бы сделал красивые блоки кода и связал директиву ref, извините:-). Быстрый google, и вы его найдете.
Таким образом, вы определенно можете использовать область изоляции и есть способы передать обратные вызовы функций в директиву, передать директивные функции ссылки из директивы, вернуться к контроллеру, двухсторонняя привязка данных и т.д. Изолировать область отлично для всего этого, но это звучит не так, как будто вы пытаетесь сделать что-то слишком сложное.
Ответ 4
В структуре Angular в шаблоне HTML вы можете получить доступ к родительской области.
Например:
<div ng-model="$parent.$parent.theModel"></div>
Это работает при создании новых областей внутри шаблона, например, ng-repeat и т.п. В теории вы можете использовать это для доступа к родительской области, которую вы хотите использовать.
Ответ 5
может быть немного уродливым, но работает:
получите элемент DOM вашей текущей директивы, перейдите назад к родительскому объекту, сделайте его angular -элементом, вызовите встроенную функцию() на нем, например.
link: function (scope, elem) {
var parentScope = angular.element ($(elem).parent()).scope();
console.log (parentScope)
}
Ответ 6
Прикосновение к родительской области может быть не лучшей идеей (я имею в виду, что это не angular способ доступа к другому слою), лучше иметь некоторые дополнительные scope.models. Во всяком случае здесь простая рабочая демонстрация.
angular.module('app', [])
.controller('ctrl', function($scope){
$scope.trDataWatch = ['item1', 'item2', 'item3'];
$scope.state = 'unrendered';
$scope.$on('ngRepeatFinished', function(){
$scope.state = 'ngRepeatFinished';
});
})
.directive('fixedColumnTooltip', function ($timeout) {
return {
restrict: 'A',
scope: {
columnselector: '@',
first: '=?',
middle: '=?',
last: '=?',
index: '=?',
odd: '=?',
even: '=?',
},
link: function (scope, element, attr) {
if(scope.last){
scope.$emit('ngRepeatFinished');
}
}
};
});
td {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<h4>{{state}}</h4>
<table>
<tr fixed-column-tooltip columnselector=".td-keyField"
ng-repeat="trData in trDataWatch"
index="$index"
odd="$odd"
even="$even"
first="$first"
middle="$middle"
last="$last">
<td>{{trData}}</td>
</tr>
</table>
</div>
Ответ 7
Если вы хотите использовать область управления с директивой, вы должны сделать следующее
app.directive('fixedColumnTooltip', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
var columnselector = attr.columnselector;
console.log(scope[columnselector]);
}
}});
Это не создаст какой-либо области для директивы, и вы все равно сможете получить доступ к значению columnselector. Если вы хотите передать функцию в columselector, тогда вы можете сделать $parse (attr.columnselector). Если это значение, тогда $parse не требуется.
Ответ 8
Когда вы определяете область действия в директиве, вы создаете область выделения. Самый простой способ передать переменную $last будет следующим атрибутом:
<tr fixed-column-tooltip columnselector=".td-keyField" ng-repeat="trData in trDataWatch" last="$last">
Ваша область действия будет выглядеть так:
scope: {
columnselector: '@',
$last: '=last'
}
ИЛИ вы можете просто получить доступ к родительской области в своей функции ссылок:
link: function (scope, element, attr) {
if (scope.$parent.$last === true) { // Will evaluate true one time
}
}
В этом случае вам не понадобится другой атрибут, и вам не нужно будет определять $last в своей области действия. JSFiddle
Ответ 9
Просто. Используйте свой аргумент атрибута для своей функции ссылок...
link: function(scope, element, attributes, ctrl) {
var selector = attributes.columnselector;
}