Как я могу использовать ng-click для директивы с изолированной областью действия?
Я могу заставить работать ng-click, когда область действия наследуется по директиве, а не когда она изолирована. UPDATE: The point is that I want the click function to be defined as part of the directive... moving the function definition into a different scope is not what I want.
Вот рабочий пример с унаследованной областью действия: https://codepen.io/anon/pen/PGBQvj
Вот сломанный пример с изолированной областью действия; https://codepen.io/anon/pen/jrpkjp
(Нажмите на цифры, они увеличиваются в первом примере, но не во втором)
Какой-то код...
HTML
<div ng-app="myApp" ng-controller="baseController">
<my-directive ng-click="hello()" current="current"></my-directive>
</div>
Директива с унаследованной областью действия:
angular.module('myApp', [])
.controller('baseController', function($scope) {
$scope.current = 1;
})
.directive('myDirective', function() {
return {
link: function(scope, element, attrs) {
scope.hello = function() {
scope.current++
};
},
replace: true,
scope: true,
template: '<div><child> <strong>{{ current }}</strong></child></div>'
}
})
.directive('child', function() {
return {
link: function(scope, element, attrs) {
console.log("horeee");
}
}
});
Та же директива, но с изолированной областью применения:
angular.module('myApp', [])
.controller('baseController', function($scope) {
$scope.current = 1;
})
.directive('myDirective', function() {
return {
link: function(scope, element, attrs) {
scope.hello = function() {
scope.current++
};
},
replace: true,
scope: {
current:'='
},
template: '<div><child> <strong>{{ current }}</strong></child></div>'
}
})
.directive('child', function() {
return {
link: function(scope, element, attrs) {
console.log("horeee");
}
}
});
6 ответов
Проблема в том, что вы пытаетесь вызвать функцию, которая не определена. Если вы хотите, чтобы логика была определена внутри изолированной директивы, нет необходимости передавать ссылку на функцию.
<my-directive current="current"></my-directive>
Ты не пройдешь ng-click="hello()"
Вот. Это сфера действия контроллера, поэтому hello()
не определено
Вместо этого переместите ng-click
событие в шаблоне директивы
template: '<div ng-click="hello()">
Еще один момент: вы используете link()
функция директивы. Это зарезервировано для манипулирования DOM. Вместо этого определите hello()
в пределах controller
функция.
controller: function ($scope) {
$scope.hello = function() {
$scope.current++
}
},
Я думаю, что здесь есть большая архитектурная проблема. Смысл изолированной директивы или компонента заключается в том, чтобы заключить внутреннюю логику в себя. Он не должен манипулировать внешним состоянием. В этом примере вы увеличиваете число. Что если в другой части вашего заявления вы хотите уменьшить число? Копирование директивы с декрементной логикой было бы большим дублированием кода.
Вместо этого вы должны определить инкремент или декремент функциональности в контроллере и передать его в директиву.
<my-directive change-number="increment()" current="current"></my-directive>
Затем используйте &
синтаксис для привязки ссылки на функцию к директиве:
scope: {
current:'=',
changeNumber: '&'
},
и позвонить changeNumber
из шаблона. Это очень облегчает повторное использование кода.
Вам нужно передать объект из контроллера в директиву
измени свой JS на
angular.module('myApp', [])
.controller('baseController', function($scope) {
$scope.current = {};
$scope.current.val=1;
})
.directive('myDirective', function() {
return {
link: function(scope, element, attrs) { scope.internalcurrent= scope.current || {};
//scope.internalcurrent.val=1;
scope.internalcurrent.hello = function() {
scope.internalcurrent.val++
};
},
replace: true,
scope: {
current:'='
},
template: '<div><child> <strong>{{ internalcurrent.val }}</strong></child></div>'
}
})
.directive('child', function() {
return {
link: function(scope, element, attrs) {
console.log("horeee");
}
}
});
и ваш HTML для
<div ng-app="myApp" ng-controller="baseController">
<my-directive ng-click="hello()" current="current"></my-directive>
</div>
Добавьте функцию приветствия к контроллеру. Позвольте ему обновить значение current и передать его в изолированную область директивы
.controller('baseController', function($scope) {
$scope.current = 1;
$scope.hello = function() {
$scope.current++;
};
})
Если вы хотите, чтобы функция click была определена в директиве, вам нужно прикрепить обработчик в шаблоне следующим образом:
template: '<div ng-click="hello()"><child><strong>{{current}}</strong></child></div>'
Когда вы присоединяете обработчик к объявлению директивы, как в вашем неработающем примере, вы в основном сообщаете ng-click, что хотите вызвать функцию в текущей области (области действия контроллера). Может показаться, что это не так, потому что в вашем рабочем примере ваша функция была определена из myDirective, но на самом деле она была присоединена к области, которая в данном случае (рабочий пример) была областью действия контроллера.
Другое решение, если вы не можете переместить «ng-click» в шаблон директивы, заключается в том, что вы можете поместить функцию в родительскую область. Так:
Заменять:
link: function(scope, element, attrs) {
scope.hello = function() {
scope.current++
};
}
Для:
link: function(scope, element, attrs) {
scope.$parent.hello = function() {
scope.current++
};
}
Это сделает функцию «привет» доступной из области контроллера.
С изолированной директивой вы можете использовать ng-click="$parent.hello()"
вместо ng-click="hello()"
, Приятно разместить ручки по вашему вопросу.
Пояснение: Когда вы используете ng-click
на элемент, значение этого (hello()
) будет оцениваться относительно его внешней области, т.е. области действия контроллера в вашем примере. Когда вы создаете директиву, которая использует неизолированную область, область действия контроллера передается link
функция и hello
определяется в области действия контроллера.
// Редактировать код:
angular.module('myApp', [])
.controller('baseController', function($scope) {
$scope.current = 1;
$scope.hello = () => $scope.current ++;
})
.directive('myDirective', function() {
return {
link: function(scope, element, attrs) {
},
replace: true,
scope: {
current:'='
},
template: '<div><child> <strong>{{ current }}</strong></child></div>'
}
})
.directive('child', function() {
return {
link: function(scope, element, attrs) {
console.log("horeee");
}
}
});