2013-04-09 4 views
38

So habe ich diese Richtlinie sagen genannt, mySave, es ist so ziemlich genau dasCallback-Funktion innerhalb Richtlinie attr in verschiedenen definierten attr

app.directive('mySave', function($http) { 
    return function(scope, element, attrs) { 
     element.bind("click", function() { 
      $http.post('/save', scope.data).success(returnedData) { 
       // callback defined on my utils service here 

       // user defined callback here, from my-save-callback perhaps? 
      } 
     }); 
    } 
}); 

das Element selbst für so aussieht

<button my-save my-save-callback="callbackFunctionInController()">save</button> 

callbackFunctionInController ist jetzt nur

$scope.callbackFunctionInController = function() { 
    alert("callback"); 
} 

wenn ich console.log()attrs.mySaveCallback innerhalb meiner-Speichern-Anweisung, gibt es nur eine Zeichenfolge callbackFunctionInController(), ich lese somewhere, dass ich $ dies analysieren sollte und es wäre in Ordnung, so versuchte ich $parse(attrs.mySaveCallback), die mir eine Funktion zurück gab, aber kaum die, die ich suchte für, gab es mir zurück

function (a,b){return m(a,b)} 

Was mache ich falsch? Ist dieser Ansatz von Anfang an fehlerhaft?

Antwort

61

So scheint was wie der beste Weg, um den isolierten Umfang verwendet, wie durch ProLoser vorgeschlagen

app.directive('mySave', function($http) { 
    return { 
     scope: { 
     callback: '&mySaveCallback' 
     } 
     link: function(scope, element, attrs) { 
     element.on("click", function() { 
      $http.post('/save', scope.$parent.data).success(returnedData) { 
       // callback defined on my utils service here 

       scope.callback(); // fires alert 
      } 
     }); 
     } 
    } 
}); 

Für Parameter zurück zum Controller tut dies

[11:28] <revolunet> you have to send named parameters 
[11:28] <revolunet> eg my-attr="callback(a, b)" 
[11:29] <revolunet> in the directive: scope.callback({a:xxx, b:yyy}) 
+0

Die Frage ist, warum Sie einen Wert an den Controller senden möchten, können Sie einfach eine Zwei-Wege-Bindung –

+0

erstellen, wenn Sie Werte zurück senden möchten Der Controller muss ein Objekt mit benannten Parametern senden, z. B .: {result: returnedData} – jujule

+2

@ArunPJohny, ein Grund, keine bidirektionale Bindung zu verwenden: Manchmal möchten Sie keine zusätzlichen Bereichseigenschaften für Werte hinzufügen, die nur benötigt werden durch die Rückruffunktion. –

9

Sie können .$eval verwenden, um eine Aussage in dem gegebenen Umfang

app.directive('mySave', function($http) { 
    return function(scope, element, attrs) { 
     $http.post('/save', scope.data).success(returnedData) { 
      // callback defined on my utils service here 

      // user defined callback here, from my-save-callback perhaps? 
      scope.$eval(attrs.mySaveCallback) 
     } 
    } 
}); 

TD auszuführen: Demo

Wenn Sie zwischen einer Richtlinie und einer Steuerung Sie den Zweiweg

Bindung verwenden können, um Daten teilen mögen
app.controller('AppController', function ($scope) { 
    $scope.callbackFunctionInController = function() { 
     console.log('do something') 
    }; 

    $scope.$watch('somedata', function(data) { 
     console.log('controller', data); 
    }, true); 
}); 

app.directive('mySave', function($http, $parse) { 
    return { 
    scope: { 
     data: '=mySaveData', 
     callback: '&mySaveCallback' //the callback 
    }, 
    link: function(scope, element, attrs) { 
     $http.get('data.json').success(function(data) { 
     console.log('data', data); 
     scope.data = data; 
     scope.callback(); //calling callback, this may not be required 
     }); 
    } 
    }; 
}); 

Demo: Fiddle

+0

Fehler: verdaut $ bereits im Gang – foxx

+0

überprüfen Sie die aktualisierte Lösung –

+0

das tatsächlich funktioniert, aber es ist der richtige Weg, es zu tun, oder isolierter Umfang wie @ProLoser vorgeschlagen noch ist die beste? Und wie würde ich returnedData zurück an mySaveCallback übergeben? – foxx

12

Es gibt viele Möglichkeiten, was Sie tun. Die erste Sache, die Sie wissen sollten, ist, dass die $http.post() aufgerufen wird, sobald das DOM-Element von der Vorlage-Engine gerendert wird, und das ist es. Wenn Sie es in eine Wiederholung einfügen, wird der Anruf für jedes neue Element im Repeater ausgeführt, also denke ich, dass dies definitiv nicht das ist, was Sie wollen. Und wenn es ist, dann entwerfen Sie wirklich Dinge nicht richtig, da die Existenz von DOM allein keine Abfragen an das Backend diktieren sollte.

Wie auch immer, direkt Ihre Frage zu beantworten; Wenn Sie die crappy Docs auf $ parse lesen, erhalten Sie einen Evaluationsausdruck. Wenn Sie diese Funktion ausführen, indem Sie den Gültigkeitsbereich an on übergeben, wird der aktuelle Status dieses Ausdrucks im übergebenen Gültigkeitsbereich zurückgegeben, dh Ihre Funktion wird ausgeführt.

var expression = $parse(attrs.mySave); 
results = expression($scope); // call on demand when needed 
expression.assign($scope, 'newValu'); // the major reason to leverage $parse, setting vals 

Ja, es ist ein wenig verwirrend auf den ersten, aber Sie müssen verstehen, dass ein $ Umfang ständig in asynchronen Anwendungen verändert und es ist alles über, wenn Sie den Wert bestimmt wollen, nicht nur, wie. $parse ist nützlicher für einen Verweis auf ein Modell, dem Sie einen Wert zuweisen und nicht nur lesen möchten.

Natürlich können Sie sich über das Erstellen eines isolieren Bereichs oder auf $eval() einen Ausdruck lesen.

$scope.$eval(attrs.mySave); 
+0

Oups, ich habe vergessen, in element.bind ("klick") auf den Beitrag beim Strippen zu setzen runter meinen Code der unnötigen Unordnung. Fixed – foxx

+0

In Ordnung, also sollte ich isolierten Bereich in erster Linie verwenden. Aber wenn ich noch "$ parse" verwenden wollte, wie würde ich dann die von $ parse zurückgegebene Funktion ausführen? Ich probierte 'callback.apply();', \t \t \t \t 'callback.call();', 'callback();', wo 'callback' ist' $ parse (attrs.mySaveCallback) ', keiner von ihnen gefeuert mein 'alert()'. – foxx

+2

@foxx, benutze parse wie folgt in deiner Link-Funktion: 'var cb = $ parse (attrs.mySaveCallback);', dann in deinem Klick callback: 'cb (scope);'. [Fiddle] (http://jsfiddle.net/mrajcok/Qak5u/) –

0
vorbei

Das ist für mich gearbeitet

In der Ansicht Skript

Innerhalb der Richtlinie

$scope[attrs.mycallbackattrib](params....); 

Es ist richtig genannt und params sind vergangen, aber vielleicht ist kein beste ‚Winkel Art und Weise‘ zu arbeiten.

+0

Nicht schön OO imo –

4
scope: { 
    callback: '&mySaveCallback' 
} 

den Umfang Einstellung explizit eine gute Lösung sein könnte, aber wenn Sie die Reichweite andere Teile des ursprünglichen Umfangs möchten, können Sie nicht, weil Sie haben es einfach überschrieben. Aus irgendeinem Grund musste ich auch andere Teile des Oszilloskops erreichen, also benutzte ich dieselbe Implementierung wie ng-click do.

Die Verwendung meiner Richtlinie in HTML:

<div my-data-table my-source="dataSource" refresh="refresh(data)">

Innerhalb der Richtlinie (ohne den Umfang ausdrücklich Einstellung):

var refreshHandler = $parse(attrs.refresh); 
    scope.$apply(function() { 
    refreshHandler({data : conditions}, scope, { $event: event }); 
}); 

Damit ich die Funktion in der Steuerung aufrufen können und Pass Parameter dazu.

In der Steuerung:

$scope.refresh= function(data){ 
    console.log(data); 
} 

Und es druckt die richtig heraus Bedingungen.

0

Sie sollten ng-click verwenden, anstatt eine eigene Direktive zu erstellen.

+0

Funktioniert in einem einfachen Fall, nicht wenn Sie möchten, wie, deaktivieren Sie die Schaltfläche und Zeug, zeigen einige Animationen, verwenden Sie die gleiche Anweisung an mehreren Orten usw. Ich erinnere mich nicht ganz, warum ich das wollte , Es ist eine Weile her. – foxx

+0

Sie können das alles mit ng-klicken. Es macht Animationen, Sie können die Schaltfläche deaktivieren. Alles. Es gibt absolut nichts in Ihrer Version, das ng-click nicht schon tut. – ProLoser

+0

Nicht sicher, warum ich downvoted wurde. Es ist eine schlechte Praxis, Geschäftslogik (wie das Speichern) in eine Richtlinie zu integrieren, die vollständig auf die Ansicht bezogen ist. Sie hätten eine $ scope.save() machen können, die einfach alles macht, was Sie wollen. – ProLoser

0
app.directive('mySave', function($http, $parse) { 
    return { 
    scope: { 
     data: '=mySaveData', 
     callback: '&' //the callback 
    }, 
    link: function(scope, element, attrs) { 
     $http.get('data.json').success(function(data) { 
     console.log('data', data); 
     if (scope.callback()) scope.callback().apply(data); 
     }); 
    } 
    }; 
});