Kann eine Winkeldirektive Argumente an Funktionen in Ausdrücken übergeben, die in den Attributen der Direktive angegeben sind?

Lesezeit: 7 Minuten

Benutzer-Avatar
Ed_

Ich habe eine Formulardirektive, die eine angegebene verwendet callback Attribut mit einem isolierten Bereich:

scope: { callback: '&' }

Es sitzt in einem ng-repeat Der Ausdruck, den ich übergebe, enthält also die id des Objekts als Argument für die Callback-Funktion:

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

Wenn ich mit der Direktive fertig bin, ruft sie $scope.callback() aus seiner Controller-Funktion. In den meisten Fällen ist das in Ordnung, und es ist alles, was ich tun möchte, aber manchmal möchte ich ein weiteres Argument aus dem hinzufügen directive selbst.

Gibt es einen Winkelausdruck, der dies ermöglichen würde: $scope.callback(arg2)ergebend callback mit angerufen werden arguments = [item.id, arg2]?

Wenn nicht, was ist der eleganteste Weg, dies zu tun?

Ich habe festgestellt, dass dies funktioniert:

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

Mit

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

und die Direktive Aufruf

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

Aber ich denke nicht, dass es besonders ordentlich ist und es beinhaltet, zusätzliche Dinge in den Isolierbereich zu stecken.

Gibt es einen besseren Weg?

Plunker Spielplatz hier (die Konsole geöffnet haben).

  • Die Attributbezeichnung “callback=” führt in die Irre. Es ist wirklich eine Rückrufauswertung, kein Rückruf selbst.

    – Dmitri Zaitsev

    12. November 2015 um 4:36 Uhr

  • @DmitriZaitsev ist ein Callback-Winkelausdruck, der zu einer JavaScript-Funktion ausgewertet wird. Ich denke, es ist ziemlich offensichtlich, dass es sich nicht um eine JavaScript-Funktion an sich handelt. Es ist nur eine Präferenz, aber ich würde es vorziehen, nicht alle meine Attribute mit “-expression” anhängen zu müssen. Dies steht im Einklang mit der ng API zum Beispiel ng-click="someFunction()" ist ein Ausdruck, der zur Ausführung einer Funktion ausgewertet wird.

    – Ed_

    12. November 2015 um 13:25 Uhr

  • Ich habe noch nie einen Winkelausdruck namens “Rückruf” gesehen. Es ist immer eine Funktion, die Sie übergeben, um aufgerufen zu werden, woher der Name kommt. Sie verwenden in Ihrem Beispiel sogar eine Funktion namens “callback”, um die Dinge noch verwirrender zu machen.

    – Dmitri Zaitsev

    12. November 2015 um 15:26 Uhr

  • Ich bin mir nicht sicher, ob Sie verwirrt sind oder ich. In meinem Beispiel $scope.callback wird durch die eingestellt callback="someFunction" Attribut und die scope: { callback: '=' } -Eigenschaft des Direktivendefinitionsobjekts. $scope.callback ist eine später aufzurufende Funktion. Das eigentliche Attribut Wert ist offensichtlich ein String – das ist bei HTML immer so.

    – Ed_

    12. November 2015 um 15:31 Uhr

  • Sie benennen sowohl Attribut als auch Funktion gleich – “Rückruf”. Das ist das Rezept für Verwirrung. Wirklich leicht zu vermeiden.

    – Dmitri Zaitsev

    12. November 2015 um 15:42 Uhr

Benutzer-Avatar
Chandermani

Wenn du deinen Callback wie von @lex82 erwähnt deklarierst like

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

Sie können die Rückrufmethode im Direktivenbereich mit der Objektzuordnung aufrufen, und die Bindung würde korrekt ausgeführt. Wie

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

ohne $parse zu erfordern. Siehe meine Geige (Konsolenprotokoll) http://jsfiddle.net/k7czc/2/

Aktualisieren: Es gibt ein kleines Beispiel dafür in der Dokumentation:

& oder &attr – bietet eine Möglichkeit, einen Ausdruck im Kontext des übergeordneten Gültigkeitsbereichs auszuführen. Wenn kein Attributname angegeben ist, wird davon ausgegangen, dass der Attributname mit dem lokalen Namen identisch ist. Gegeben und Widget-Definition des Geltungsbereichs: { localFn:’&myAttr’ }, dann isoliert die Geltungsbereichseigenschaft localFn auf einen Funktions-Wrapper für den Ausdruck count = count + value. Oft ist es wünschenswert, Daten aus dem isolierten Gültigkeitsbereich über einen Ausdruck und an den übergeordneten Gültigkeitsbereich zu übergeben. Dies kann durch Übergabe einer Zuordnung lokaler Variablennamen und -werte an den Ausdrucks-Wrapper fn erfolgen. Wenn der Ausdruck beispielsweise increment(amount) ist, können wir den Betragswert angeben, indem wir localFn als localFn({amount: 22}) aufrufen.

  • Sehr schön! Ist das irgendwo dokumentiert?

    – ach

    17. Oktober 2014 um 20:09 Uhr

  • Ich denke nicht, dass dies eine gute Lösung ist, da Sie in der Direktivendefinition manchmal nicht wissen, welcher Parameter übergeben werden muss.

    – OMGPOP

    2. Juli 2015 um 6:58 Uhr

  • Dies ist eine gute Lösung und vielen Dank dafür, aber ich glaube, die Antwort muss ein wenig überarbeitet werden. Wer ist lex82 und was hat er erwähnt?

    – Wturm

    17. Dezember 2016 um 21:29 Uhr

  • Interessanter Ansatz. Was passiert jedoch, wenn Sie zulassen möchten, dass eine Funktion mit einem beliebigen Parameter (oder mehreren) übergeben wird? Sie wissen nichts über die Funktion oder ihre Parameter und müssen sie bei einem Ereignis innerhalb der Direktive ausführen. Wie geht man vor? Zum Beispiel könnten Sie bei einer Direktive onchangefunc=’myCtrlFunc(dynamicVariableHere)’ haben.

    – Zugoase

    22. Januar 2018 um 8:08 Uhr

An den anderen Antworten ist nichts auszusetzen, aber ich verwende die folgende Technik, wenn ich Funktionen in einem Direktivenattribut übergebe.

Lassen Sie die Klammer weg, wenn Sie die Direktive in Ihren HTML-Code einfügen:

<my-directive callback="someFunction" />

Dann “entpacken” Sie die Funktion im Link oder Controller Ihrer Direktive. Hier ist ein Beispiel:

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

Der Schritt “Unwrapping” ermöglicht es, die Funktion mit einer natürlicheren Syntax aufzurufen. Es stellt auch sicher, dass die Direktive ordnungsgemäß funktioniert, selbst wenn sie in anderen Direktiven verschachtelt ist, die die Funktion möglicherweise übergeben. Wenn Sie das Auspacken nicht durchgeführt haben, dann haben Sie ein Szenario wie dieses:

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

Dann würden Sie so etwas in Ihrer inneren Direktive erhalten:

callback()()()(data); 

Was in anderen Verschachtelungsszenarien fehlschlagen würde.

Ich habe diese Technik aus einem ausgezeichneten Artikel von Dan Wahlin unter adaptiert http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-3-isolate-scope-and-function-parameters

Ich habe den Unwrapping-Schritt hinzugefügt, um das Aufrufen der Funktion natürlicher zu gestalten und das Verschachtelungsproblem zu lösen, auf das ich in einem Projekt gestoßen bin.

  • Ein netter Ansatz, aber ich bin nicht in der Lage, den zu verwenden this Zeiger innerhalb der Callback-Methode, da sie den Gültigkeitsbereich der Direktive verwendet. Ich verwende Typescript und mein Callback sieht so aus: 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; }

    – nee

    24. Juni 2015 um 9:05 Uhr


  • Hinweis: Wenn Sie verschachtelte Direktiven haben und den Callback nach oben weitergeben möchten, müssen Sie jede Direktive auspacken, nicht nur die, die den Callback auslöst.

    – Folgex

    28. August 2015 um 13:15 Uhr

Benutzer-Avatar
Ben

In der Direktive (myDirective):

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

In Richtlinienvorlage:

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

In der Quelle:

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

…wo myFunction ist in der Steuerung definiert.

Beachten Sie, dass param in der Richtlinie Vorlage bindet ordentlich an param in der Quelle und ist auf eingestellt item.


Um von innerhalb der anzurufen link Eigenschaft einer Direktive (“innerhalb” davon), verwenden Sie einen sehr ähnlichen Ansatz:

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

  • Während Sie In source: bound-function=’myFunction(obj1.param, obj2.param)’> haben, wie gehen Sie dann vor?

    – Ankit Pandey

    13. Januar 2020 um 8:25 Uhr

Ja, es gibt einen besseren Weg: Sie können die verwenden $parse-Dienst in Ihrer Direktive, um einen Ausdruck im Kontext des übergeordneten Bereichs auszuwerten, während bestimmte Bezeichner im Ausdruck an Werte gebunden werden, die nur innerhalb Ihrer Direktive sichtbar sind:

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

Fügen Sie diese Zeile zur Link-Funktion der Direktive hinzu, wo Sie auf die Attribute der Direktive zugreifen können.

Ihr Callback-Attribut kann dann wie folgt gesetzt werden callback = "callback(item.id, arg2)" weil arg2 durch den $parse-Dienst innerhalb der Direktive an yourSecondArgument gebunden ist. Direktiven wie ng-click ermöglichen Ihnen den Zugriff auf das Click-Ereignis über die $event Bezeichner innerhalb des Ausdrucks, der an die Direktive übergeben wird, indem genau dieser Mechanismus verwendet wird.

Beachten Sie, dass Sie dies nicht tun müssen callback ein Mitglied Ihres isolierten Geltungsbereichs mit dieser Lösung.

Bei mir hat folgendes funktioniert:

in der Direktive deklarieren Sie es so:

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

Verwenden Sie es in der Direktivenvorlage wie folgt:

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

Und dann, wenn Sie die Direktive verwenden, übergeben Sie die Funktion wie folgt:

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

Sie übergeben die Funktion durch ihre Deklaration und sie wird von der Direktive aufgerufen und die Parameter werden ausgefüllt.

1280740cookie-checkKann eine Winkeldirektive Argumente an Funktionen in Ausdrücken übergeben, die in den Attributen der Direktive angegeben sind?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy