Угловая директива, внедряющая элемент 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" директивы.

Относительный ответ

Другие вопросы по тегам