Угловая директива, внедряющая элемент DOM с событием click
Содержание отредактировано
Цель состоит в том, чтобы создать директиву, которая может быть присоединена к текстовому полю, которое, когда текстовое поле имеет фокус, после текстового поля появится изображение / кнопка, и событие щелчка по изображению / кнопке вызовет функцию, содержащуюся в директиве. Цель состоит в том, чтобы эта функция была полностью автономной в директиве, чтобы ее можно было легко развернуть во многих страницах или приложениях.
Изображение / кнопка появляется после текстового поля без проблем, но событие нажатия кнопки не запускает функцию. Я создал plunkr с примером кода.
В начале строки 15 определяется функция, называемая "поиск", которая не делает ничего, кроме запуска оповещения. Когда текстовое поле имеет фокус, кнопка появляется, как и ожидалось, и строка 34 успешно вызывает функцию поиска, что означает, что сама функция работает. Однако событие нажатия кнопки не запускает функцию поиска.
Оригинальный пост
Я пытаюсь воссоздать некоторые функциональные возможности в наших приложениях, которые в настоящее время выполняются с помощью jQuery. Функциональность включает в себя присоединение псевдокласса к текстовому полю, которое затем выбирается jQuery, и изображение лупы вводится в DOM сразу после текстового поля. При нажатии на изображение открывается диалоговое окно.
До сих пор я достиг простой HTML-страницы, простого контроллера и простой директивы. Когда текстовое поле имеет фокус, изображение выглядит так, как ожидается. Однако директива ng-click не срабатывает.
Вот HTML:
<input
id="txtAlias"
type="text"
ng-model="pc.results"
user-search />
</div>
Вот контроллер:
angular
.module('app')
.controller('PeopleController', PeopleController);
PeopleController.$inject = ['$http'];
function PeopleController() {
var pc = this;
pc.results = '';
pc.search = function () {
alert('test');
};
}
И это директива:
angular
.module('app')
.directive('userSearch', userSearch);
function userSearch($compile) {
return {
restrict: 'EAC',
require: 'ngModel',
//transclude: true,
scope: {
//search : function(callerid){
// alert(callerid);
//}
},
template: "The user's alias is: <b><span ng-bind='pc.results'></span>.",
//controller: UserSearchController,
link: function (scope, element, attrs) {
element.bind('focus', function () {
//alert(attrs.id + ' || ' + attrs.userSearch);
var nextElement = element.parent().find('.openuserdialog').length;
if (nextElement == 0) {
var magnifyingglass = $compile('<img src="' + homePath + 'Images/zoomHS.png" ' +
'alt="User Search" ' +
'ng-click="pc.search("' + attrs.id + '")" ' +
'class="openuserdialog">')(scope);
element.after(magnifyingglass);
}
});
}
};
};
В настоящее время я был бы рад получить оповещение о срабатывании, нажав pc.search в контроллере или выполнив поиск в изолированной области. Пока что ни один из них не сработал. Я уверен, что чего-то не хватает, но я не могу понять, что.
Решение
Спасибо пользователю на форуме Google, который показал мне свойство controllerAs для директив. Эта версия теперь отлично работает:
angular
.module('app')
.directive('userSearch', userSearch);
function userSearch($compile){
return {
controller: function ()
{
this.search = function () {
alert('Test');
};
},
link: function (scope, element, attrs) {
element.bind('focus', function () {
var nextElement = element.parent().find('.openuserdialog').length;
if (nextElement === 0) {
var btn = '<img src="' + homePath + 'Images/zoomHS.png" ' +
'ng-click="userSearch.search()" ' +
'class="openuserdialog" />';
element.after($compile(btn)(scope));
}
});
},
controllerAs: 'userSearch'
};
};
2 ответа
Вместо того, чтобы пытаться внедрить в DOM, а затем пытаться подключиться к той вещи, которую вы только что внедрили, оберните как вход, так и кнопку / значок поиска в директиве. Вы можете использовать изолированную область видимости и двустороннюю привязку, чтобы соединить как вход, так и кнопку:
HTML:
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<search-box data="name" search-function="search"></search-box>
</body>
Вот и контроллер, и директива, демонстрирующая это. Обратите внимание на "=" в изолированной области, создавая двустороннюю привязку к соответствующим атрибутам, когда директива используется в шаблоне.
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.search= function() { alert('search clicked'); }
});
app.directive('searchBox', function() {
return {
restrict: 'E',
scope: {
searchFunction: '=',
data: '=',
},
template: '<input ng-model="data" /><button ng-click="searchFunction()">Search</button>'
}
})
Вы должны быть в состоянии легко заменить button
элемент с img
или что еще хочет твое сердце.
Вот план с предупреждением () для поля поиска, и где ввод в текстовое поле в директиве влияет на соответствующее свойство области видимости контроллера: http://plnkr.co/edit/0lj4AmjOgwNZ2DJMSHDj
Вы используете изолированную область в своей директиве, что означает, что у нее нет доступа к родительской области. Так что в этом случае вам нужно явно передать ссылку на ваш метод в директиву. Передана ссылка на метод в вашей области действия директивы с помощью новой переменной внутри изолированной области действия директивы.
наценка
<input id="txtAlias"
type="text" ng-model="pc.results"
user-search search="search(id)" />
scope: {
search: '&'
}
Поскольку у вас нет доступа к родительской области, вы не можете использовать псевдоним контроллера там, как вы используете pc.
, Просто используйте следующее без псевдонима. Таким образом, директива будет напрямую связывать эти переменные из области действия директивы.
template: "The user's alias is: <b><span ng-bind='results'></span>.",
Также измените шаблон компиляции на
if (nextElement == 0) {
var magnifyingglass = $compile('<img src="' + homePath + 'Images/zoomHS.png" ' +
'alt="User Search" ' +
'ng-click="search({id: ' + attrs.id + '})' +
'class="openuserdialog">')(scope);
element.after(magnifyingglass);
}
Скорее я хотел бы иметь скомпилированный шаблон как часть template
только из директивной функции. И я покажу и скрою это на основе ng-if="expression"
директивы.