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>

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

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

Ответы:


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


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"}.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.