Ich habe versucht, eine kleine Direktive zu schreiben, um ihren Inhalt mit einer anderen Vorlagendatei zu versehen.
Dieser Code:
<layout name="Default">My cool content</layout>
Sollte diese Ausgabe haben:
<div class="layoutDefault">My cool content</div>
Weil das Layout "Standard" diesen Code hat:
<div class="layoutDefault">{{content}}</div>
Hier der Code der Richtlinie:
app.directive('layout', function($http, $compile){
return {
restrict: 'E',
link: function(scope, element, attributes) {
var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default';
$http.get(scope.constants.pathLayouts + layoutName + '.html')
.success(function(layout){
var regexp = /^([\s\S]*?){{content}}([\s\S]*)$/g;
var result = regexp.exec(layout);
var templateWithLayout = result[1] + element.html() + result[2];
element.html($compile(templateWithLayout)(scope));
});
}
}
});
Mein Problem:
Wenn ich Bereichsvariablen in der Vorlage verwende (in der Layoutvorlage oder innerhalb des Layout-Tags), z. {{whatever}}
es funktioniert nur anfangs. Wenn ich die whatever
Variable aktualisiere, wird die Direktive nicht mehr aktualisiert. Die gesamte Link-Funktion wird nur einmal ausgelöst.
Ich denke, dass AngularJS nicht weiß, dass diese Direktive Bereichsvariablen verwendet und daher nicht aktualisiert wird. Aber ich habe keine Ahnung, wie ich dieses Verhalten beheben kann.
$compile
) die Uhr nicht automatisch eingerichtet wird. Wie Sie sagen, ist es zunächst gebunden ...Antworten:
Sie sollten eine gebundene Bereichsvariable erstellen und ihre Änderungen beobachten:
return { restrict: 'E', scope: { name: '=' }, link: function(scope) { scope.$watch('name', function() { // all the code here... }); } };
quelle
scope
und nicht$scope
. Innerhalb derlink
Funktion ist der Bereich eine einfache Variable.Ich brauchte auch eine Lösung für dieses Problem und habe die Antworten in diesem Thread verwendet, um Folgendes zu finden:
.directive('tpReport', ['$parse', '$http', '$compile', '$templateCache', function($parse, $http, $compile, $templateCache) { var getTemplateUrl = function(type) { var templateUrl = ''; switch (type) { case 1: // Table templateUrl = 'modules/tpReport/directives/table-report.tpl.html'; break; case 0: templateUrl = 'modules/tpReport/directives/default.tpl.html'; break; default: templateUrl = ''; console.log("Type not defined for tpReport"); break; } return templateUrl; }; var linker = function (scope, element, attrs) { scope.$watch('data', function(){ var templateUrl = getTemplateUrl(scope.data[0].typeID); var data = $templateCache.get(templateUrl); element.html(data); $compile(element.contents())(scope); }); }; return { controller: 'tpReportCtrl', template: '<div>{{data}}</div>', // Remove all existing content of the directive. transclude: true, restrict: "E", scope: { data: '=' }, link: linker }; }]) ;
In Ihr HTML aufnehmen:
<tp-report data='data'></tp-report>
Diese Anweisung wird zum dynamischen Laden von Berichtsvorlagen verwendet, die auf dem vom Server abgerufenen Dataset basieren.
Es setzt eine Überwachung auf die Eigenschaft scope.data und lädt bei jeder Aktualisierung (wenn der Benutzer ein neues Dataset vom Server anfordert) die entsprechende Anweisung, um die Daten anzuzeigen.
quelle
Sie müssen Angular mitteilen, dass Ihre Direktive eine Bereichsvariable verwendet:
Sie müssen eine Eigenschaft des Gültigkeitsbereichs an Ihre Direktive binden:
return { restrict: 'E', scope: { whatever: '=' }, ... }
und dann ist
$watch
es:$scope.$watch('whatever', function(value) { // do something with the new value });
Weitere Informationen finden Sie in der Angular-Dokumentation zu Anweisungen .
quelle
Ich habe eine viel bessere Lösung gefunden:
app.directive('layout', function(){ var settings = { restrict: 'E', transclude: true, templateUrl: function(element, attributes){ var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default'; return constants.pathLayouts + layoutName + '.html'; } } return settings; });
Der einzige Nachteil, den ich derzeit sehe, ist die Tatsache, dass transkludierte Vorlagen ihren eigenen Umfang haben. Sie erhalten die Werte von ihren Eltern, aber anstatt den Wert im Elternteil zu ändern, wird der Wert in einem eigenen, neuen untergeordneten Bereich gespeichert. Um dies zu vermeiden, verwende ich jetzt
$parent.whatever
anstelle vonwhatever
.Beispiel:
<layout name="Default"> <layout name="AnotherNestedLayout"> <label>Whatever:</label> <input type="text" ng-model="$parent.whatever"> </layout> </layout>
quelle
Sie sollten Ihr Zielfernrohr im Auge behalten.
So können Sie es machen:
<layout layoutId="myScope"></layout>
Ihre Richtlinie sollte so aussehen
app.directive('layout', function($http, $compile){ return { restrict: 'E', scope: { layoutId: "=layoutId" }, link: function(scope, element, attributes) { var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default'; $http.get(scope.constants.pathLayouts + layoutName + '.html') .success(function(layout){ var regexp = /^([\s\S]*?){{content}}([\s\S]*)$/g; var result = regexp.exec(layout); var templateWithLayout = result[1] + element.html() + result[2]; element.html($compile(templateWithLayout)(scope)); }); } } $scope.$watch('myScope',function(){ //Do Whatever you want },true)
Ebenso können Sie Modelle in Ihrer Direktive verwenden. Wenn das Modell also automatisch aktualisiert wird, aktualisiert Ihre Überwachungsmethode Ihre Direktive.
quelle
Ich weiß, dass dies ein altes Thema ist, aber falls jemand dies wie ich findet:
Ich habe den folgenden Code verwendet, als ich meine Direktive zum Aktualisieren von Werten benötigte, als der "übergeordnete Bereich" aktualisiert wurde. Bitte korrigieren Sie mich auf jeden Fall, wenn ich etwas falsch mache, da ich immer noch eckig lerne, aber dies hat getan, was ich brauchte;
Richtlinie:
directive('dateRangePrint', function(){ return { restrict: 'E', scope:{ //still using the single dir binding From: '@rangeFrom', To: '@rangeTo', format: '@format' }, controller: function($scope, $element){ $scope.viewFrom = function(){ return formatDate($scope.From, $scope.format); } $scope.viewTo = function(){ return formatDate($scope.To, $scope.format); } function formatDate(date, format){ format = format || 'DD-MM-YYYY'; //do stuff to date... return date.format(format); } }, replace: true, // note the parenthesis after scope var template: '<span>{{ viewFrom() }} - {{ viewTo() }}</span>' } })
quelle
Wir können das versuchen
$scope.$apply(function() { $scope.step1 = true; //scope.list2.length = 0; });
http://jsfiddle.net/Etb9d/
quelle
Eine einfache Lösung ist es, den Umfang variabel zu machen Objekt . Dann greifen Sie mit auf den Inhalt zu
{{ whatever-object.whatever-property }}
. Die Variable wird nicht aktualisiert, da JavaScript den primitiven Typ als Wert übergibt . Während Objekte als Referenz übergeben werden , löst dies das Problem.quelle
Ich bin mir nicht sicher, warum noch niemand vorgeschlagen hat
bindToController
, all diese hässlichen zu entfernen,scopes and $watches.
wenn Sie verwendenAngular 1.4
Unten ist ein Beispiel-DOM:
<div ng-app="app"> <div ng-controller="MainCtrl as vm"> {{ vm.name }} <foo-directive name="vm.name"></foo-directive> <button ng-click="vm.changeScopeValue()"> changeScopeValue </button> </div> </div>
Folgt dem
controller
Code:angular.module('app', []); // main.js function MainCtrl() { this.name = 'Vinoth Initial'; this.changeScopeValue = function(){ this.name = "Vinoth has Changed" } } angular .module('app') .controller('MainCtrl', MainCtrl); // foo.js function FooDirCtrl() { } function fooDirective() { return { restrict: 'E', scope: { name: '=' }, controller: 'FooDirCtrl', controllerAs: 'vm', template:'<div><input ng-model="name"></div>', bindToController: true }; } angular .module('app') .directive('fooDirective', fooDirective) .controller('FooDirCtrl', FooDirCtrl);
Eine Geige zum Herumspielen, hier ändern wir den Scope-Wert im
controller
und automatisch imdirective updates on scope change
. http://jsfiddle.net/spechackers/1ywL3fnq/quelle