AngularJS - передать функцию в директиву

160

У меня есть пример angularJS

<div ng-controller="testCtrl">

<test color1="color1" updateFn="updateFn()"></test>
</div>
 <script>
  angular.module('dr', [])
.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function() {
        alert('123');
    }
})
.directive('test', function() {
    return {
        restrict: 'E',
        scope: {color1: '=',
                updateFn: '&'},
        template: "<button ng-click='updateFn()'>Click</button>",
        replace: true,
        link: function(scope, elm, attrs) { 
        }
    }
});

</script>
</body>

</html>

Я хочу, чтобы при нажатии кнопки появлялось окно с предупреждением, но ничего не показывалось.

Может кто-нибудь помочь мне?

user2707026
источник

Ответы:

243

Чтобы вызвать функцию контроллера в родительской области изнутри директивы изолирующей области, используйте dash-separatedимена атрибутов в HTML, как указано в OP.

Также, если вы хотите отправить параметр в вашу функцию, вызовите функцию, передав объект:

<test color1="color1" update-fn="updateFn(msg)"></test>

JS

var app = angular.module('dr', []);

app.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function(msg) {        
        alert(msg);
    }
});

app.directive('test', function() {
    return {
        restrict: 'E',
        scope: {
            color1: '=',
            updateFn: '&'
        },
        // object is passed while making the call
        template: "<button ng-click='updateFn({msg : \"Hello World!\"})'>
            Click</button>",
        replace: true,        
        link: function(scope, elm, attrs) {             
        }
    }
});

Fiddle

AlwaysALearner
источник
1
Спасибо Codezilla за ваш ответ, и я хочу спросить об обстоятельствах, когда я хочу связать функцию "updateFn" с родительской областью, чтобы изолировать область в директиве "test", возможно ли это?
user2707026
2
replaceАтрибут устарел в AngularJS: stackoverflow.com/questions/24194972/...
cdmckay
8
по какой-то причине аргумент для меня не определен.
Чови
1
@chovy Я думаю, что аргумент используется только после повторного вызова метода? Первое использование открытой скобки, кажется, является форматом, который angular хочет, чтобы метод был просто передан, но я могу ошибаться там
marksyzm
1
Отображение объекта updateFn({msg: 'my message'});должно использоваться в этом формате при вызове функции внутри функции директивы link.
Брайан
159

Возможно, я чего-то упускаю, но хотя другие решения действительно вызывают функцию родительского контекста, нет возможности передавать аргументы из кода директивы, это потому, что update-fn, например, вызывается updateFn()с фиксированными параметрами {msg: "Hello World"}. Небольшое изменение позволяет директиве передавать аргументы, что я считаю гораздо более полезным.

<test color1="color1" update-fn="updateFn"></test>

Обратите внимание, что HTML передает ссылку на функцию, т.е. без ()скобок.

JS

var app = angular.module('dr', []);

app.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function(msg) {        
        alert(msg);
    }
});

app.directive('test', function() {
    return {
        restrict: 'E',
        scope: {
            color1: '=',
            updateFn: '&'
        },
        // object is passed while making the call
        template: "<button ng-click='callUpdate()'>
            Click</button>",
        replace: true,        
        link: function(scope, elm, attrs) {       
          scope.callUpdate = function() {
            scope.updateFn()("Directive Args");
          }
        }
    }
});

Таким образом, в приведенном выше callUpdateпримере HTML вызывает локальную функцию области, которая затем «выбирает» updateFn из родительской области и вызывает возвращенную функцию с параметрами, которые может сгенерировать директива.

http://jsfiddle.net/mygknek2/

Стив
источник
9
Не уверен, как я могу получить отрицательный голос за то, что работает ?? Вы должны оставить комментарий, если будете голосовать против.
Стив
7
Это сработало для меня. Если вам не нужна дополнительная функция, просто напишитеng-click="updateFn()('Directive Args')"
Грэм Уолтерс
7
Ой! scope.updateFn () ("Директивные аргументы"); !! НЕ scope.updateFn («Директивные аргументы»); !!!
Фунг Д.,
2
Это действительно более совершенный ответ!
Винеш
11
@ Ludwik11 уверен - это потому, что видимость scope.updateFn - это функция, которая возвращает функцию (отсюда () ()), и это потому, что мы передаем в область видимости (через update-fn = "updateFn" в html) ссылку к функции, которую мы хотим вызвать. 1st () - это вызов angular для возврата этой ссылки, 2nd () - это вызов нашей функции и мы передаем любые параметры. HTH
Стив
39

В вашем HTML-теге директивы test имя атрибута функции не должно быть camelCased, а основано на дефисе.

так что вместо:

<test color1="color1" updateFn="updateFn()"></test>

записывать:

<test color1="color1" update-fn="updateFn()"></test>

Это угловой способ определить разницу между атрибутами директивы (такими как функция update-fn) и функциями.

Офер Сегев
источник
1
спасибо за улов. Я включил это в свой ответ. Проголосовал! :)
AlwaysALearner
10

Как насчет передачи функции контроллера с двунаправленной привязкой ? Затем вы можете использовать его в директиве точно так же, как и в обычном шаблоне (для простоты я удалил ненужные части):

<div ng-controller="testCtrl">

   <!-- pass the function with no arguments -->
   <test color1="color1" update-fn="updateFn"></test>
</div>

<script>
   angular.module('dr', [])
   .controller("testCtrl", function($scope) {
      $scope.updateFn = function(msg) {
         alert(msg);
      }
   })
   .directive('test', function() {
      return {
         scope: {
            updateFn: '=' // '=' bidirectional binding
         },
         template: "<button ng-click='updateFn(1337)'>Click</button>"
      }
   });
</script>

Я приземлился на этот вопрос, потому что я попробовал описанный выше метод, но как-то это не сработало. Теперь это работает отлично.

Мартон Тамас
источник
5

используйте тире и нижний регистр для имени атрибута (как сказали другие ответы):

 <test color1="color1" update-fn="updateFn()"></test>

И используйте «=» вместо «&» в директиве:

 scope: { updateFn: '='}

Тогда вы можете использовать updateFn как любую другую функцию:

 <button ng-click='updateFn()'>Click</button>

Вот и вы!

Джейн
источник
5
Почему вы используете «=» вместо «&»? когда я пытался это делать, он постоянно вызывал мою функцию.
user1012500
2
Неправильно использовать «=» для этого. Это для двухсторонней привязки объекта.
Бен Талиадорос
1
Думаю, единственной проблемой является использование скобок в первом шаблоне. Это выполняет функцию, затем связывает результат. Вместо этого Вы должны передать только имя функции, например:update-fn="updateFn"
Мартон Тамас
1
Плохой ответ очень плохо.
Towry
4

Мне пришлось использовать привязку "=" вместо "&", потому что это не сработало. Странное поведение.

Гюнтер Рейницер
источник
2
Это потому, что вы, скорее всего, передаете директиву ссылку на функцию JS вместо выполнения. Когда вы передаете функцию в качестве аргумента директиве, update-fn="updateFn()"вы должны включить круглые скобки (и, возможно, params). Передача его в качестве ссылки на функцию update-fn="updateFn"не будет работать с &привязкой
JorgeGRC
0

@JorgeGRC Спасибо за ваш ответ. Одна вещь, хотя, «возможно», часть очень важна. Если у вас есть параметр (ы), вы должны также включить его / их в свой шаблон и обязательно указать свои местные жители, например updateFn({msg: "Directive Args"}.

user2893858
источник