Функция директивного вызова angularjs, указанная в атрибуте, и передает ей аргумент

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

<div my-method='theMethodToBeCalled'></div>

В функции связи я связываюсь с событием jQuery, которое передает аргумент, мне нужно перейти к функции:

app.directive("myMethod",function($parse) {
  restrict:'A',
  link:function(scope,element,attrs) {
     var expressionHandler = $parse(attrs.myMethod);
     $(element).on('theEvent',function( e, rowid ) {
        id = // some function called to determine id based on rowid
        scope.$apply(function() {expressionHandler(id);});
     }
  }
}

app.controller("myController",function($scope) {
   $scope.theMethodToBeCalled = function(id) { alert(id); };
}

Без передачи id я могу заставить его работать, но как только я попытаюсь передать аргумент, функция больше не вызывается

Ответ 1

Марко хорошо работает.

В отличие от рекомендуемого способа Angular (как показано treeface plunkr) используется выражение обратного вызова, которое не требует определения выраженияHandler. В примере с шаблоном marko:

В шаблоне

<div my-method="theMethodToBeCalled(myParam)"></div>

В функции директивной ссылки

$(element).click(function( e, rowid ) {
  scope.method({myParam: id});
});

У этого есть один недостаток по сравнению с решением marko - при первой загрузке функцияMethodToBeCalled будет вызываться с помощью myParam === undefined.

Рабочий экзамен можно найти на @treeface Plunker

Ответ 2

Просто добавьте некоторую информацию к другим ответам - использование & - хороший способ, если вам нужна изолированная область.

Основной недостаток решения marko заключается в том, что он заставляет вас создавать изолированную область действия для элемента, но вы можете иметь только один из них в элементе (иначе вы столкнетесь с ошибкой angular: несколько директив [ директива1, директива2] с просьбой об изолированном объеме)

Это означает, что вы:

  • не может использовать его в элементе hat имеет изолированную область действия
  • не может использовать две директивы с этим решением на одном элементе

Поскольку исходный вопрос использует директиву с restrict:'A', обе ситуации могут возникать довольно часто в больших приложениях, и использование изолированной области здесь не является хорошей практикой, а также ненужной. На самом деле у rekna была хорошая интуиция в этом случае, и почти она работала, единственное, что он делал неправильно, - это неправильная функция $parsed (см., Что она возвращает здесь: https://docs.angularjs.org/api/ng/service/$parse).

TL; DR; Исправлен код вопроса

<div my-method='theMethodToBeCalled(id)'></div>

и код

app.directive("myMethod",function($parse) {
  restrict:'A',
  link:function(scope,element,attrs) {
     // here you can parse any attribute (so this could as well be,
     // myDirectiveCallback or multiple ones if you need them )
     var expressionHandler = $parse(attrs.myMethod);
     $(element).on('theEvent',function( e, rowid ) {
        calculatedId = // some function called to determine id based on rowid

        // HERE: call the parsed function correctly (with scope AND params object)
        expressionHandler(scope, {id:calculatedId});
     }
  }
}

app.controller("myController",function($scope) {
   $scope.theMethodToBeCalled = function(id) { alert(id); };
}

Ответ 3

Не зная точно, что вы хотите сделать... но все же здесь возможное решение.

Создайте область с свойством '&' - в локальной области. Он предоставляет способ выполнения выражения в контексте родительской области "(подробнее см. директивная документация).

Я также заметил, что вы использовали функцию стенографической ссылки и сунули в атрибутах объекта там. Вы не можете этого сделать. Более ясно (imho) просто вернуть объект определения директивы. См. Мой код ниже.

Здесь пример кода и fiddle.

<div ng-app="myApp">
<div ng-controller="myController">
    <div my-method='theMethodToBeCalled'>Click me</div>
</div>
</div>

<script>

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

   app.directive("myMethod",function($parse) {
       var directiveDefinitionObject = {
         restrict: 'A',
         scope: { method:'&myMethod' },
         link: function(scope,element,attrs) {
            var expressionHandler = scope.method();
            var id = "123";

            $(element).click(function( e, rowid ) {
               expressionHandler(id);
            });
         }
       };
       return directiveDefinitionObject;
   });

   app.controller("myController",function($scope) {
      $scope.theMethodToBeCalled = function(id) { 
          alert(id); 
      };
   });

</script>

Ответ 4

Вы можете создать директиву, которая выполняет вызов функции с параметрами, используя attrName: "&" для ссылки на выражение во внешней области.

Мы хотим заменить директиву ng-click на ng-click-x:

<button ng-click-x="add(a,b)">Add</button>

Если у нас была эта область:

$scope.a = 2;
$scope.b = 2;

$scope.add = function (a, b) {
  $scope.result = parseFloat(a) + parseFloat(b);
}

Мы могли бы написать нашу директиву так:

angular.module("ng-click-x", [])

.directive('ngClickX', [function () {

  return {

    scope: {

      // Reference the outer scope
      fn: "&ngClickX",

    },

    restrict: "A",

    link: function(scope, elem) {

      function callFn () {
        scope.$apply(scope.fn());
      }

      elem[0].addEventListener('click', callFn);
    }
  };
}]);

Вот живая демонстрация: http://plnkr.co/edit/4QOGLD?p=info

Ответ 5

Вот что сработало для меня.

Html с использованием директивы

 <tr orderitemdirective remove="vm.removeOrderItem(orderItem)" order-item="orderitem"></tr>

Html директивы: orderitem.directive.html

<md-button type="submit" ng-click="remove({orderItem:orderItem})">
       (...)
</md-button>

Область действия директивы:

scope: {
    orderItem: '=',
    remove: "&",

Ответ 6

Мое решение:

  • на полимере поднять событие (например, complete)
  • определить директиву, связывающую событие с функцией управления

Директива

/*global define */
define(['angular', './my-module'], function(angular, directives) {
    'use strict';
    directives.directive('polimerBinding', ['$compile', function($compile) {

            return {
                 restrict: 'A',
                scope: { 
                    method:'&polimerBinding'
                },
                link : function(scope, element, attrs) {
                    var el = element[0];
                    var expressionHandler = scope.method();
                    var siemEvent = attrs['polimerEvent'];
                    if (!siemEvent) {
                        siemEvent = 'complete';
                    }
                    el.addEventListener(siemEvent, function (e, options) {
                        expressionHandler(e.detail);
                    })
                }
            };
        }]);
});

Полимерный компонент

<dom-module id="search">

<template>
<h3>Search</h3>
<div class="input-group">

    <textarea placeholder="search by expression (eg. temperature>100)"
        rows="10" cols="100" value="{{text::input}}"></textarea>
    <p>
        <button id="button" class="btn input-group__addon">Search</button>
    </p>
</div>
</template>

 <script>
  Polymer({
    is: 'search',
            properties: {
      text: {
        type: String,
        notify: true
      },

    },
    regularSearch: function(e) {
      console.log(this.range);
      this.fire('complete', {'text': this.text});
    },
    listeners: {
        'button.click': 'regularSearch',
    }
  });
</script>

</dom-module>

Страница

 <search id="search" polimer-binding="searchData"
 siem-event="complete" range="{{range}}"></siem-search>

searchData - управляющая функция

$scope.searchData = function(searchObject) {
                    alert('searchData '+ searchObject.text + ' ' + searchObject.range);

}

Ответ 7

Это должно работать.

<div my-method='theMethodToBeCalled'></div>

app.directive("myMethod",function($parse) {
  restrict:'A',
  scope: {theMethodToBeCalled: "="}
  link:function(scope,element,attrs) {
     $(element).on('theEvent',function( e, rowid ) {
        id = // some function called to determine id based on rowid
        scope.theMethodToBeCalled(id);
     }
  }
}

app.controller("myController",function($scope) {
   $scope.theMethodToBeCalled = function(id) { alert(id); };
}