fungsi panggilan direktif angularjs ditentukan dalam atribut dan meneruskan argumen ke sana


102

Saya ingin membuat arahan yang menautkan ke atribut. Atribut menentukan fungsi yang harus dipanggil pada ruang lingkup. Tapi saya juga ingin meneruskan argumen ke fungsi yang ditentukan di dalam fungsi link.

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

Dalam fungsi tautan, saya mengikat ke acara jQuery, yang meneruskan argumen yang harus saya teruskan ke fungsi:

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

Tanpa meneruskan id, saya bisa membuatnya berfungsi, tetapi begitu saya mencoba memberikan argumen, fungsi tersebut tidak dipanggil lagi


Bagaimana cara mengakses properti objek melalui lingkup isolate tanpa pengikatan dua arah? saya pikir itu membantu. menggunakan lingkup terisolasi, dan memanggil lingkup induk melalui $ scope. $ parent
JJbang

Jawaban:


98

Solusi Marko bekerja dengan baik .

Untuk membedakan dengan cara Angular yang direkomendasikan (seperti yang ditunjukkan oleh plunkr treeface) adalah dengan menggunakan ekspresi callback yang tidak memerlukan definisi ekspresiHandler. Dalam contoh perubahan marko:

Dalam template

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

Dalam fungsi tautan direktif

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

Ini memang memiliki satu kelemahan dibandingkan dengan solusi marko - pada pemuatan pertama fungsiMethodToBeCalled akan dipanggil dengan myParam === undefined.

Contoh yang berfungsi dapat ditemukan di @treeface Plunker


Memang, pola pemberian nama fungsi dengan parameter di atribut khusus ini tampaknya merupakan cara termudah dan terkuat untuk menentukan "fungsi panggilan balik" dalam arahan ... thx !!
rekna

3
Sangat membingungkan untuk memanggil "setProduct" 2 hal yang berbeda - fungsi atribut dan cakupan, membuatnya sangat sulit untuk memahami yang mana.
Dmitri Zaitsev

Yang membingungkan adalah mengapa jawaban yang benar menggunakan lingkup isolasi tetapi pertanyaannya tidak. Atau apakah saya melewatkan sesuatu?
j_walker_dev

Dari pengujian saya menggunakan kode ini di sudut 1.2.28, itu bekerja dengan baik. Pengujian saya tidak memanggil theMethodToBeCalled dengan undefined pada pemuatan pertama. Begitu pula dengan contoh plunker. Ini sepertinya tidak menjadi masalah. Dengan kata lain, ini tampaknya menjadi pendekatan yang benar ketika Anda ingin meneruskan parameter ke tautan direktif (dalam lingkup terisolasi). Saya sarankan memperbarui komentar tentang kerugian dan myParam === tidak ditentukan.
jazeee

Ini "Ini memang memiliki satu kelemahan dibandingkan dengan solusi marko - pada pemuatan pertama fungsiMethodToBeCalled akan dipanggil dengan myParam === undefined" tidak terjadi dalam kasus saya .... saya kira ada beberapa konteks implisit di sini
Victor

95

Hanya untuk menambahkan beberapa info ke jawaban lain - menggunakan &adalah cara yang baik jika Anda membutuhkan ruang lingkup yang terisolasi.

Kelemahan utama dari solusi marko adalah ia memaksa Anda untuk membuat ruang lingkup terisolasi pada sebuah elemen, tetapi Anda hanya dapat memiliki salah satu dari mereka pada sebuah elemen (jika tidak, Anda akan mengalami kesalahan bersudut: Beberapa direktif [direktif1, direktif2] bertanya untuk ruang lingkup terisolasi )

Ini artinya kamu :

  • tidak dapat menggunakannya pada topi elemen yang memiliki ruang lingkup terisolasi itu sendiri
  • tidak dapat menggunakan dua arahan dengan solusi ini pada elemen yang sama

Karena pertanyaan asli menggunakan arahan dengan restrict:'A'kedua situasi mungkin cukup sering muncul dalam aplikasi yang lebih besar, dan menggunakan lingkup terisolasi di sini bukanlah praktik yang baik dan juga tidak perlu. Faktanya rekna memiliki intuisi yang baik dalam hal ini, dan hampir berhasil, satu-satunya kesalahan yang dilakukannya adalah memanggil fungsi $ parsed salah (lihat apa yang dikembalikan di sini: https://docs.angularjs.org/api/ ng / service / $ parse ).

TL; DR; Kode pertanyaan tetap

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

dan kodenya

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 Memang - tidak perlu mengisolasi ruang lingkup - jauh lebih bersih!
Dmitri Zaitsev

bagaimana jika atribut hanya berisi nama metode, seperti <div my-method = 'theMethodToBeCalled'> </div> atau fungsi sebaris seperti <div my-method = 'alert ("hi");'> </div>
Jonathan.

1
Jika Anda mengalami masalah dengan salah satu pendekatan ini, perlu diingat bahwa metode yang dipanggil harus tersedia dalam cakupan yang Anda teruskan ke fungsi yang dikembalikan $parse.
ragamufin

Jawaban ini persis seperti yang saya cari +1
grimmdude

apa acaranya"? Bagaimana cara menjalankan fungsi pada div turunan?
Shlomo

88

Tidak tahu persis apa yang ingin Anda lakukan ... tetapi berikut adalah solusi yang mungkin.

Buat lingkup dengan properti '&' - dalam lingkup lokal. Ini "menyediakan cara untuk mengeksekusi ekspresi dalam konteks cakupan induk" (lihat dokumentasi direktif untuk detailnya).

Saya juga memperhatikan bahwa Anda menggunakan fungsi penghubung singkat dan memasukkan atribut objek di sana. Kamu tidak boleh melakukan itu. Lebih jelas (imho) hanya mengembalikan objek definisi direktif. Lihat kode saya di bawah ini.

Ini contoh kode dan biola .

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

Fungsi dipanggil, ketika saya menyetel $ scope.id = id di dalam theMethodToBeCalled, tampilan tidak diperbarui. Mungkin saya perlu membungkus ekspresiHandler (id) di dalam scope.apply.
rekna

2
Luar biasa ini membantu saya menemukan solusi untuk masalah saya. Perlu disebutkan bahwa Anda hanya perlu melakukan ini di tingkat atas jika Anda melakukan serangkaian arahan yang lebih dalam. Pertimbangkan ini: plnkr.co/edit/s3y67iGL12F2hDER2RNl?p=preview di mana saya meneruskan metode melalui dua arahan.
permukaan pohon

3
Dan inilah cara kedua (mungkin lebih bersudut) untuk melakukannya: plnkr.co/edit/r9CV9Y1RWRuse4RwFPka?p=preview
treeface

1
Bagaimana saya bisa melakukannya tanpa isolasi ruang lingkup?
Evan Lévesque

3
+1 karena solusi ini mengajari saya bahwa saya perlu memanggil scope.method (); pertama untuk mendapatkan referensi sebenarnya ke metode tersebut.
Sal

6

Anda bisa membuat direktif yang menjalankan panggilan fungsi dengan params dengan menggunakan attrName: "&"to mereferensikan ekspresi di lingkup luar.

Kami ingin mengganti ng-clickdirektif dengan ng-click-x:

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

Jika kami memiliki ruang lingkup ini:

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

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

Kita bisa menulis arahan kita seperti ini:

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

Ini adalah demo langsung: http://plnkr.co/edit/4QOGLD?p=info


2

Inilah yang berhasil untuk saya.

Html menggunakan direktif

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

HTML direktif: orderitem.directive.html

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

Ruang lingkup arahan:

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

0

Solusi saya:

  1. pada polimer mengangkat suatu peristiwa (misalnya complete)
  2. mendefinisikan arahan yang menghubungkan acara ke fungsi kontrol

Pengarahan

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

Komponen polimer

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

Halaman

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

searchData adalah fungsi kontrol

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

}

-2

Ini seharusnya berhasil.

<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); };
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.