angularjs yönerge çağrısı işlevi öznitelikte belirtilir ve ona bir argüman iletir


103

Bir özniteliğe bağlanan bir yönerge oluşturmak istiyorum. Özellik, kapsamda çağrılması gereken işlevi belirtir. Ama aynı zamanda link fonksiyonu içinde belirlenen fonksiyona bir argüman iletmek istiyorum.

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

Link işlevinde, işleve iletmem gereken bir argüman ileten bir jQuery olayına bağlanıyorum:

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

Kimliği geçmeden onu çalıştırabilirim, ancak bir argüman iletmeye çalıştığım anda işlev artık çağrılmıyor


iki yönlü bağlama olmadan izole kapsamı aracılığıyla nesne özelliğine nasıl erişilir? yardımcı olduğunu düşünüyorum. izole kapsamı kullanın ve $ kapsam
JJbang

Yanıtlar:


98

Marko'nun çözümü iyi çalışıyor .

Önerilen Angular yolla (ağaç yüzeyin plunkr ile gösterildiği gibi) tezat oluşturmak, expressionHandler öğesinin tanımlanmasını gerektirmeyen bir geri arama ifadesi kullanmaktır. Marko'nun örnek değişikliğinde:

Şablonda

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

Yönerge bağlantı işlevinde

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

Marko'nun çözümüne kıyasla bunun bir dezavantajı vardır - ilk yüklemedeMethodToBeCalled işlevi myParam === tanımsız olarak çağrılacaktır.

Bir çalışma exampe bulunabilir @treeface Plunker


Nitekim, özel öznitelikte parametre ile işlev adı sağlamanın bu modeli, yönergelerde "geri arama işlevlerini" tanımlamanın en kolay ve en sağlam yolu gibi görünüyor ... thx !!
rekna

3
"SetProduct" 2 farklı şey çağırmak çok kafa karıştırıcı - öznitelik ve kapsam işlevi, hangisinin nerede olduğunu anlamayı gerçekten zorlaştırıyor.
Dmitri Zaitsev

Kafa karıştırıcı olan şey, doğru cevabın izole kapsamı kullanmasının nedenidir, ancak soru bu değildir. Yoksa bir şey mi kaçırıyorum?
j_walker_dev

Bu kodu 1.2.28 açısalında kullanan testlerimden iyi çalışıyor. Testlerim ilk yüklemede tanımsız olarak theMethodToBeCalled'ı çağırmıyor. Plunker örneği de öyle. Bu bir problem gibi görünmüyor. Diğer bir deyişle, parametreleri yönerge bağlantısına (ayrı bir kapsamda) geçirmek istediğinizde bu doğru yaklaşım gibi görünmektedir. Dezavantaj ve myParam === undefined ile ilgili yorumu güncellemenizi tavsiye ederim.
jazeee

Bu "Marko'nun çözümüne kıyasla bunun bir dezavantajı var - ilk yüklemede MethodToBeCalled işlevi myParam === undefined ile çalıştırılacak" benim durumumda gerçekleşmiyor .... sanırım burada bazı örtük bağlam var
Victor

95

Diğer cevaplara biraz bilgi eklemek için - &izole bir kapsama ihtiyacınız varsa kullanmak iyi bir yoldur.

Marko'nun çözümünün ana dezavantajı, sizi bir öğe üzerinde yalıtılmış bir kapsam oluşturmaya zorlamasıdır, ancak bir öğede bunlardan yalnızca birine sahip olabilirsiniz (aksi takdirde açısal bir hatayla karşılaşırsınız: Birden çok yönerge [yönerge1, yönerge2] izole kapsam için )

Bunun anlamı siz:

  • onu bir element üzerinde kullanamazsın, şapka izole edilmiş bir kapsama sahiptir
  • bu çözümle aynı öğe üzerinde iki yönerge kullanılamaz

Orijinal soru restrict:'A'her iki durumda da bir yönerge kullandığından , daha büyük uygulamalarda oldukça sık ortaya çıkabilir ve burada yalıtılmış bir kapsam kullanmak iyi bir uygulama değildir ve ayrıca gereksizdir. Aslında rekna bu durumda iyi bir sezgiye sahipti ve neredeyse çalışıyordu, yanlış yaptığı tek şey $ ayrıştırılmış işlevi yanlış olarak adlandırmaktı (burada ne döndürdüğüne bakın: https://docs.angularjs.org/api/ ng / hizmet / $ ayrıştırma ).

TL; DR; Sabit soru kodu

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

ve kod

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 Gerçekten - kapsamı izole etmeye gerek yok - çok daha temiz!
Dmitri Zaitsev

ya özellik yalnızca <div my-method = 'theMethodToBeCalled'> </div> gibi yöntem adını veya <div my-method = 'alert ("hi");'> </div> gibi bir satır içi işlevi içeriyorsa
Jonathan.

1
Bu yaklaşımlardan herhangi biriyle sorun yaşıyorsanız, çağrılan yöntemin, geri döndürülen işleve ilettiğiniz kapsamda mevcut olması gerektiğini unutmayın $parse.
ragamufin

Bu cevap tam olarak aradığım
şeydi

olay nedir"? İşlevi bir alt div üzerinde nasıl çalıştırabilirim?
Shlomo

88

Tam olarak ne yapmak istediğinizi bilmemek ... ama yine de olası bir çözüm burada.

Yerel kapsamda '&' özelliğine sahip bir kapsam oluşturun. "Üst kapsam bağlamında bir ifade yürütmenin bir yolunu sağlar" (ayrıntılar için yönerge belgelerine bakın).

Ayrıca bir steno bağlama işlevi kullandığınızı ve burada nesne niteliklerini ittiğinizi fark ettim. Bunu yapamazsınız. Direktif tanım nesnesini döndürmek daha açıktır (imho). Aşağıdaki koduma bakın.

İşte bir kod örneği ve bir keman .

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

İşlev çağrılıyor, MethodToBeCalled içinde $ kapsam.id = id belirlediğimde görünüm güncellenmiyor. Muhtemelen expressionHandler'ı (id) kapsam.apply içine sarmam gerekiyor.
rekna

2
Harika bu, sorunuma çözüm bulmama yardımcı oldu. Daha derin bir yönerge dizisi yapıyorsanız bunu yalnızca en üst düzeyde yapmanız gerektiğini belirtmekte fayda var. Şunu düşünün: plnkr.co/edit/s3y67iGL12F2hDER2RNl?p=preview yöntemi iki yönergeden geçirdiğim yere.
2013

3
Ve işte bunu yapmanın ikinci (belki de daha açısal) bir yolu: plnkr.co/edit/r9CV9Y1RWRuse4RwFPka?p=preview
treeface

1
Kapsam izolasyonu olmadan bunu nasıl yapabilirim?
Evan Lévesque

3
+1 çünkü bu çözüm bana kapsam.method () 'u çağırmam gerektiğini öğretti; önce yönteme gerçek referansı almak için.
Sal

6

attrName: "&"Dış kapsamdaki ifadeye başvurmak için parametresini kullanarak params ile bir işlev çağrısı yürüten bir yönerge oluşturabilirsiniz .

ng-clickDirektifi şu şekilde değiştirmek istiyoruz ng-click-x:

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

Bu kapsamımız olsaydı:

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

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

Direktifimizi şöyle yazabiliriz:

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

İşte canlı bir demo: http://plnkr.co/edit/4QOGLD?p=info


2

İşte benim için ne işe yaradı.

Yönergeyi kullanan html

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

Yönergenin HTML'si: orderitem.directive.html

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

Direktifin kapsamı:

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

0

Çözümüm:

  1. polimerde bir olay (ör. complete)
  2. olayı kontrol işlevine bağlayan bir yönerge tanımlayın

Direktif

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

Polimer bileşen

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

Sayfa

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

searchData kontrol işlevi

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

}

-2

Bu çalışmalı.

<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); };
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.