Hàm gọi chỉ thị anglejs được chỉ định trong thuộc tính và truyền một đối số cho nó


102

Tôi muốn tạo một chỉ thị liên kết đến một thuộc tính. Thuộc tính chỉ định hàm nên được gọi trên phạm vi. Nhưng tôi cũng muốn truyền một đối số cho hàm được xác định bên trong hàm liên kết.

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

Trong hàm liên kết, tôi liên kết với một sự kiện jQuery, sự kiện này sẽ chuyển một đối số mà tôi cần chuyển cho hàm:

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); };
}

Không cần truyền id, tôi có thể làm cho nó hoạt động, nhưng ngay sau khi tôi cố gắng truyền một đối số, hàm không được gọi nữa


làm thế nào để truy cập thuộc tính đối tượng thông qua phạm vi cô lập mà không có ràng buộc hai chiều? tôi nghĩ nó hữu ích. sử dụng phạm vi bị cô lập và gọi phạm vi chính thông qua $ scope. $ parent
JJbang

Câu trả lời:


98

Giải pháp của Marko hoạt động tốt .

Để tương phản với cách Angular được đề xuất (như được hiển thị bằng plunkr của treeface) là sử dụng biểu thức gọi lại không yêu cầu xác định biểu thứcHandler. Trong ví dụ thay đổi của marko:

Trong mẫu

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

Trong chức năng liên kết chỉ thị

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

Điều này có một nhược điểm so với giải pháp của marko - trong lần tải đầu tiên, hàmMethodToBeCalled sẽ được gọi với myParam === không xác định.

Bạn có thể tìm thấy một exampe đang hoạt động tại @treeface Plunker


Thật vậy, mô hình cung cấp tên hàm với tham số trong thuộc tính tùy chỉnh dường như là cách dễ nhất và mạnh mẽ nhất để xác định "hàm gọi lại" trong chỉ thị ... thx !!
rekna

3
Rất khó hiểu khi gọi "setProduct" 2 thứ khác nhau - hàm thuộc tính và phạm vi, khiến bạn thực sự khó hiểu cái nào ở đâu.
Dmitri Zaitsev

Điều khó hiểu là tại sao câu trả lời đúng là sử dụng phạm vi cô lập nhưng câu hỏi thì không. Hay tôi đang thiếu cái gì đó?
j_walker_dev

Từ các thử nghiệm của tôi bằng cách sử dụng mã này trong góc 1.2.28, nó hoạt động tốt. Các thử nghiệm của tôi không gọi theMethodToBeCalled với không xác định trong lần tải đầu tiên. Ví dụ về plunker cũng vậy. Đây không phải là một vấn đề. Nói cách khác, đây có vẻ là cách tiếp cận chính xác khi bạn muốn chuyển các tham số vào liên kết chỉ thị (trong một phạm vi cô lập). Tôi khuyên bạn nên cập nhật nhận xét về nhược điểm và myParam === không xác định.
jazeee

Điều này "Điều này không có một điểm bất lợi so với giải pháp của marko - trong lần tải đầu tiên, hàmMethodToBeCalled sẽ được gọi với myParam === undefined" không xảy ra trong trường hợp của tôi .... tôi đoán có một số ngữ cảnh ngầm ở đây
Victor

95

Chỉ để thêm một số thông tin vào các câu trả lời khác - sử dụng &là một cách tốt nếu bạn cần một phạm vi riêng biệt.

Nhược điểm chính của giải pháp của marko là nó buộc bạn phải tạo một phạm vi cô lập trên một phần tử, nhưng bạn chỉ có thể có một trong những phạm vi đó trên một phần tử (nếu không bạn sẽ gặp phải lỗi góc cạnh: Nhiều chỉ thị [chỉ thị1, chỉ thị2] yêu cầu cho phạm vi cô lập )

Nó nghĩa là bạn :

  • không thể sử dụng nó trên mũ nguyên tố có phạm vi riêng biệt
  • không thể sử dụng hai chỉ thị với giải pháp này trên cùng một phần tử

Vì câu hỏi ban đầu sử dụng một chỉ thị với restrict:'A'cả hai tình huống có thể xuất hiện khá thường xuyên trong các ứng dụng lớn hơn và việc sử dụng một phạm vi riêng biệt ở đây không phải là một thực tiễn tốt và cũng không cần thiết. Thực tế rekna có một trực giác tốt trong trường hợp này, và gần như nó đã hoạt động, điều duy nhất anh ấy làm sai là gọi sai hàm $ parsed (xem nó trả về ở đây: https://docs.angularjs.org/api/ ng / service / $ parse ).

TL; DR; Đã sửa mã câu hỏi

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

và mã

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); };
}

11
+1 Thật vậy - không cần phải cô lập phạm vi - sạch hơn nhiều!
Dmitri Zaitsev

điều gì sẽ xảy ra nếu thuộc tính chỉ chứa tên phương thức, như <div my-method = 'theMethodToBeCalled'> </div> hoặc một hàm nội tuyến như <div my-method = 'alert ("hi");'> </div>
Jonathan.

1
Nếu bạn gặp sự cố với bất kỳ cách tiếp cận nào trong số này, hãy nhớ rằng phương thức đang được gọi phải có sẵn trong phạm vi mà bạn chuyển cho hàm được trả về từ đó $parse.
ragamufin

Câu trả lời này chính xác là những gì tôi đang tìm kiếm +1
Grimmdude

"theEvent" là gì? Làm cách nào để thực thi hàm trên div con?
Shlomo

88

Không biết chính xác bạn muốn làm gì ... nhưng đây vẫn là một giải pháp khả thi.

Tạo phạm vi với thuộc tính '&' - trong phạm vi cục bộ. Nó "cung cấp một cách để thực thi một biểu thức trong ngữ cảnh của phạm vi cha" (xem tài liệu hướng dẫn để biết chi tiết).

Tôi cũng nhận thấy rằng bạn đã sử dụng một hàm liên kết tốc ký và đưa các thuộc tính đối tượng vào đó. Bạn không thể làm điều đó. Rõ ràng hơn (imho) chỉ trả về đối tượng định nghĩa chỉ thị. Xem mã của tôi bên dưới.

Đây là một mẫu mã và một trò chơi .

<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>

Hàm được gọi, khi tôi đặt $ scope.id = id bên trongMethodToBeCalled, chế độ xem không được cập nhật. Có thể tôi cần bọc biểu thứcHandler (id) bên trong scope.apply.
rekna

2
Tuyệt vời, điều này đã giúp tôi tìm ra giải pháp cho vấn đề của mình. Điều đáng nói là bạn chỉ cần làm điều này ở cấp cao nhất nếu bạn đang thực hiện một tổ hợp các lệnh sâu hơn. Hãy xem xét điều này: plnkr.co/edit/s3y67iGL12F2hDER2RNl?p=preview nơi tôi truyền phương thức qua hai chỉ thị.
treeface

3
Và đây là một giây (có lẽ góc cạnh hơn) cách để làm việc đó: plnkr.co/edit/r9CV9Y1RWRuse4RwFPka?p=preview
treeface

1
Làm thế nào tôi có thể làm điều đó mà không bị cô lập phạm vi?
Evan Lévesque

3
+1 vì giải pháp này đã dạy tôi rằng tôi cần gọi scope.method (); đầu tiên để có được tham chiếu thực tế cho phương pháp.
Sal

6

Bạn có thể tạo một chỉ thị thực hiện lệnh gọi hàm với các attrName: "&"tham số bằng cách sử dụng tham chiếu biểu thức trong phạm vi bên ngoài.

Chúng tôi muốn thay thế ng-clickchỉ thị bằng ng-click-x:

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

Nếu chúng ta có phạm vi này:

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

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

Chúng tôi có thể viết chỉ thị của mình như vậy:

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);
    }
  };
}]);

Đây là bản demo trực tiếp: http://plnkr.co/edit/4QOGLD?p=info


2

Đây là những gì làm việc cho tôi.

Html bằng cách sử dụng lệnh

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

Html của chỉ thị: orderitem.directive.html

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

Phạm vi của Chỉ thị:

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

0

Giải pháp của tôi:

  1. trên polyme nêu lên một sự kiện (ví dụ. complete)
  2. xác định một chỉ thị liên kết sự kiện với chức năng điều khiển

Chỉ thị

/*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);
                    })
                }
            };
        }]);
});

Thành phần polyme

<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>

Trang

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

searchData là chức năng điều khiển

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

}

-2

Điều này sẽ hoạt động.

<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); };
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.