Açısal bir yönerge, yönerge niteliklerinde belirtilen ifadelerdeki işlevlere argümanlar iletebilir mi?


160

callbackAyrı tutma kapsamı ile belirtilen bir özniteliği kullanan bir form yönergesi var :

scope: { callback: '&' }

İçinde oturduğum ng-repeatifade id, nesnenin geri çağırma işlevine argüman olarak içerdiği şekilde oturur :

<directive ng-repeat = "item in stuff" callback = "callback(item.id)"/>

Yönerge ile işim bittiğinde $scope.callback(), denetleyici işlevinden çağırır . Çoğu durumda bu iyi ve yapmak istediğim tek şey, ama bazen directivekendi içinden başka bir argüman eklemek istiyorum .

Bu izin verecek bir açısal ifadesi var mıdır: $scope.callback(arg2), sonuçlanan callbackile çağrılan arguments = [item.id, arg2]?

Değilse, bunu yapmanın en güzel yolu nedir?

Bunun işe yaradığını gördüm:

<directive 
  ng-repeat = "item in stuff" 
  callback = "callback" 
  callback-arg="item.id"/>

İle

scope { callback: '=', callbackArg: '=' }

ve direktif çağrısı

$scope.callback.apply(null, [$scope.callbackArg].concat([arg2, arg3]) );

Ama bence özellikle düzgün ve ayrı bir kapsamda fazladan şeyler koymayı içeriyor.

Daha iyi bir yol var mı?

Burada Plunker oyun alanı (konsolu açın).


"Callback =" öznitelik adı yanlış yönlendiriyor. Gerçekten bir geri arama değerlendirmesi, geri aramanın kendisi değil.
Dmitri Zaitsev

@DmitriZaitsev bir JavaScript işlevi için değerlendirilecek bir geri arama açısal ifadesidir. Kendi başına bir JavaScript işlevi olmadığı oldukça açıktır. Bu sadece bir tercih ama tüm niteliklerimi "-expression" ile sonlandırmamayı tercih ederim. Bu, ngAPI ile tutarlıdır, örneğin ng-click="someFunction()"bir işlevi yürütmeyi değerlendiren bir ifadedir.
Ed Hinchliffe

"Geri arama" adı verilen Açısal ifadeyi hiç görmedim. Adı her zaman çağrılmak için geçtiğiniz bir işlevdir. İşleri daha da karmaşık hale getirmek için örneğinizde "geri arama" adı verilen bir işlev bile kullanıyorsunuz.
Dmitri Zaitsev

Kafanın karışıp karışmadığından emin değilim. Benim örnekte $scope.callbacktarafından ayarlanır callback="someFunction"özniteliği ve scope: { callback: '=' }direktif tanımı nesnesinin özelliği. $scope.callback olan daha sonraki bir tarihte çağrılacak bir işlev. Asıl öznitelik değeri açıkça bir dizedir - bu her zaman HTML'de geçerlidir.
Ed Hinchliffe

Hem özniteliği hem de işlevi aynı şekilde adlandırırsınız - "geri arama". Bu kafa karışıklığının tarifi. Gerçekten kaçınmak kolay.
Dmitri Zaitsev

Yanıtlar:


215

Geri aramanızı @ lex82 tarafından belirtildiği gibi bildirirseniz

callback = "callback(item.id, arg2)"

Nesne eşlemesi ile yönerge kapsamındaki geri çağrı yöntemini çağırabilirsiniz ve bağlamayı doğru şekilde yapar. Sevmek

scope.callback({arg2:"some value"});

$ ayrıştırma gerektirmeden. Kemanımı görün (konsol günlüğü) http://jsfiddle.net/k7czc/2/

Güncelleme : Belgede bunun küçük bir örneği var :

& veya & attr - üst kapsam bağlamında bir ifade yürütmenin bir yolunu sağlar. Hiçbir attr adı belirtilmezse, öznitelik adının yerel adla aynı olduğu varsayılır. Scope: {localFn: '& myAttr'} ifadesi verildiğinde ve widget tanımında, localFn kapsam özelliğini yalıtmak count = count + value ifadesi için bir işlev sarmalayıcısına işaret edecektir. Genellikle, izole edilen kapsamdan bir ifade ve ana kapsama veri aktarımı arzu edilir, bu, yerel değişken adlarının ve değerlerinin bir haritasını ifade sarmalayıcısına fn geçirerek yapılabilir. Örneğin, ifade artış (miktar) ise, localFn değerini localFn ({amount: 22}) olarak çağırarak miktar değerini belirtebiliriz.


4
Çok hoş! Bu herhangi bir yerde belgelenmiş mi?
ach

12
Bunun iyi bir çözüm olduğunu düşünmüyorum çünkü yönerge tanımında bazen geçilecek parametrenin ne olduğunu bilemezsiniz.
OMGPOP

Bu iyi bir çözüm ve bunun için teşekkür ederim, ama cevabın biraz gelgit gerektirdiğine inanıyorum. Lex82 kimdir ve ne demişti?
Aralık'ta Wtower

İlginç bir yaklaşım. HERHANGİ bir parametre (veya çoklu) ile herhangi bir işlevin geçirilmesine izin vermek istediğinizde ne olur? Fonksiyonun ve parametrelerinin hiçbirini bilmiyorsunuz ve direktif içindeki bazı olaylarda çalıştırmanız gerekiyor. Bu nasıl yapılır? Örneğin, bir yönergede onchangefunc = 'myCtrlFunc (dynamicVariableHere)' olabilir
trainoasis

58

Diğer cevaplarda yanlış olan bir şey yok, ancak direktif niteliğindeki işlevleri iletirken aşağıdaki tekniği kullanıyorum.

Html'nize yönergeyi eklerken parantezinizi bırakın:

<my-directive callback="someFunction" />

Ardından, yönerge bağlantınızdaki veya denetleyicideki işlevi "açın". işte bir örnek:

app.directive("myDirective", function() {

    return {
        restrict: "E",
        scope: {
            callback: "&"                              
        },
        template: "<div ng-click='callback(data)'></div>", // call function this way...
        link: function(scope, element, attrs) {
            // unwrap the function
            scope.callback = scope.callback(); 

            scope.data = "data from somewhere";

            element.bind("click",function() {
                scope.$apply(function() {
                    callback(data);                        // ...or this way
                });
            });
        }
    }
}]);    

"Paketin açılması" adımı, işlevin daha doğal bir sözdizimi kullanılarak çağrılmasını sağlar. Ayrıca, işlevi geçebilecek diğer direktiflerin içine yerleştirilmiş olsa bile direktifin düzgün çalışmasını sağlar. Açma işlemini yapmadıysanız, böyle bir senaryo varsa:

<outer-directive callback="someFunction" >
    <middle-directive callback="callback" >
        <inner-directive callback="callback" />
    </middle-directive>
</outer-directive>

O zaman iç direktifinizde böyle bir şeyle sonuçlanırsınız:

callback()()()(data); 

Hangi diğer yuvalama senaryolarında başarısız olur.

Bu tekniği http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-3-isolate-scope-and-function-parameters adresindeki Dan Wahlin'in mükemmel bir makalesinden uyarladım

İşlevi daha doğal hale getirmek ve bir projede karşılaştığım yuvalama sorununu çözmek için çözme adımını ekledim.


2
Güzel bir yaklaşım, ancak thisyönergelerin kapsamını kullandığı için işaretçiyi geri arama yönteminin içinde kullanamıyorum . public validateFirstName(firstName: string, fieldName: string): ng.IPromise<boolean> { var deferred = this.mQService.defer<boolean>(); ... .then(() => deferred.resolve(true)) .catch((msg) => { deferred.reject(false); }); return deferred.promise; }
Typescript

1
Uyarı: Yuvalanmış yönergeleriniz varsa ve geri aramayı yukarı doğru yaymak istiyorsanız, yalnızca bir geri çağrıyı tetikleyen değil, her yönergede açmanız gerekir.
Episodex

43

Yönerge ( myDirective):

...
directive.scope = {  
    boundFunction: '&',
    model: '=',
};
...
return directive;

Yönerge şablonunda:

<div 
data-ng-repeat="item in model"  
data-ng-click='boundFunction({param: item})'>
{{item.myValue}}
</div>

Kaynak:

<my-directive 
model='myData' 
bound-function='myFunction(param)'>
</my-directive>

...nerede myFunction denetleyicide tanımlanır.

O Not paramyönergesi şablon bağlar düzgünce için paramkaynakta ve ayarlandığında item.


linkBir direktifin mülkiyetinden ("içi") aramak için çok benzer bir yaklaşım kullanın:

...
directive.link = function(isolatedScope) {
    isolatedScope.boundFunction({param: "foo"});
};
...
return directive;

Kaynak yaparken: bound-function = 'myFunction (obj1.param, obj2.param)'> sonra nasıl devam edilir?
Ankit Pandey

15

Evet, daha iyi bir yol var: Yönergenizdeki $ parse hizmetini , ifadedeki belirli tanımlayıcıları yalnızca yönergenizde görünen değerlere bağlarken üst kapsam bağlamındaki bir ifadeyi değerlendirmek için kullanabilirsiniz:

$parse(attributes.callback)(scope.$parent, { arg2: yourSecondArgument });

Bu satırı, direktifin özniteliklerine erişebileceğiniz direktifin link işlevine ekleyin.

Geri arama özniteliğiniz daha sonra callback = "callback(item.id, arg2)", arg2, yönerge içindeki $ parse hizmeti tarafındanSecondArgument öğenize bağlı olduğu için ayarlanabilir. Direktifleri sever ng-clicksen yoluyla tıkla olayı erişmesine izin$event yönergeler tam olarak bu mekanizmayı kullanarak yönerge aktarılan ifade içindeki tanımlayıcı .

callbackBu çözümle izole kapsamınızın bir üyesini oluşturmanıza gerek olmadığını unutmayın .


3
Kullanma scope.$parentdirektifi "sızdıran" yapar - iyi tasarlanmış kapsüllenmiş bir bileşenin yapmaması gereken dış dünyayı çok fazla "bilir".
Dmitri Zaitsev

3
Bir üst kapsamı olduğunu biliyor ancak kapsamdaki belirli bir alana erişmediği için bunun tolere edilebilir olduğunu düşünüyorum.
lex82

0

Benim için aşağıdaki çalıştı:

direktifte şöyle bildiriniz:

.directive('myDirective', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            myFunction: '=',
        },
        templateUrl: 'myDirective.html'
    };
})  

Yönerge şablonunda aşağıdaki şekilde kullanın:

<select ng-change="myFunction(selectedAmount)">

Ve sonra yönergeyi kullandığınızda, işlevi şu şekilde iletin:

<data-my-directive
    data-my-function="setSelectedAmount">
</data-my-directive>

İşlevi bildirimiyle iletirsiniz ve direktiften çağrılır ve parametreler doldurulur.

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.