webentwicklung-frage-antwort-db.com.de

Die AngularJS-Direktive wird bei Änderungen der Gültigkeitsbereichsvariablen nicht aktualisiert

Ich habe versucht, eine kleine Direktive zu schreiben, deren Inhalt mit einer anderen Vorlagendatei verpackt wird.

Dieser Code:

<layout name="Default">My cool content</layout>

Sollte diese Ausgabe haben:

<div class="layoutDefault">My cool content</div>

Weil das Layout "Default" diesen Code hat:

<div class="layoutDefault">{{content}}</div>

Hier der Code der Direktive:

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 anfangs einfach. Wenn ich die Variable whatever 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.

65
Armin

Sie sollten eine gebundene Bereichsvariable erstellen und deren Änderungen beobachten:

return {
   restrict: 'E',
   scope: {
     name: '='
   },
   link: function(scope) {
     scope.$watch('name', function() {
        // all the code here...
     });
   }
};
79
QuarK

Ich brauchte auch eine Lösung für dieses Problem und verwendete die Antworten in diesem Thread, 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
        };
    }])
    ;

Fügen Sie in Ihre HTML ein:

<tp-report data='data'></tp-report>

Diese Anweisung wird zum dynamischen Laden von Berichtsvorlagen verwendet, die auf der vom Server abgerufenen Datenmenge basieren.

Sie legt eine Überwachung für die scope.data -Eigenschaft fest und lädt bei jeder Aktualisierung (wenn der Benutzer eine neue Datenmenge vom Server anfordert) die entsprechende Anweisung, um die Daten anzuzeigen.

41
Roy Milder

Sie müssen Angular mitteilen, dass Ihre Anweisung eine Bereichsvariable verwendet:

Sie müssen einige Eigenschaften des Bereichs an Ihre Direktive binden:

return {
    restrict: 'E',
    scope: {
      whatever: '='
    },
   ...
}

und dann $watch es:

  $scope.$watch('whatever', function(value) {
    // do something with the new value
  });

Weitere Informationen finden Sie in der Angular-Dokumentation zu Richtlinien .

16
Paul Mougel

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 transklusive Vorlagen ihren eigenen Geltungsbereich haben. Sie erhalten die Werte von ihren Eltern, aber anstatt den Wert im übergeordneten Element zu ändern, wird der Wert in einem eigenen neuen untergeordneten Bereich gespeichert. Um dies zu vermeiden, verwende ich jetzt $parent.whatever anstelle von whatever.

Beispiel:

<layout name="Default">
    <layout name="AnotherNestedLayout">
        <label>Whatever:</label>
        <input type="text" ng-model="$parent.whatever">
    </layout>
</layout>
8
Armin

Sie sollten Ihren Umfang überwachen.

So kannst du es machen:

<layout layoutId="myScope"></layout>

Ihre Anweisung sollte 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)

In ähnlicher Weise können Sie auch Modelle in Ihrer Direktive verwenden. Wenn also Modellaktualisierungen automatisch vorgenommen werden, aktualisiert Ihre Überwachungsmethode Ihre Direktive.

2
Aditya Sethi

Ich weiß, dass dies ein altes Thema ist, aber falls jemand das wie ich findet:

Ich habe den folgenden Code verwendet, als ich meine Direktive brauchte, um Werte zu aktualisieren, wenn der "übergeordnete Bereich" aktualisiert wurde. Bitte korrigieren Sie mich auf jeden Fall, wenn ich etwas Falsches mache, da ich immer noch eckig lerne.

direktive: 

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>'
    }
})
1
slappy-x

Wir können das versuchen

$scope.$apply(function() {
    $scope.step1 = true;
    //scope.list2.length = 0;
});

http://jsfiddle.net/Etb9d/

0
build-1

Eine einfache Lösung besteht darin, die Gültigkeitsbereichvariable object festzulegen. Greifen Sie dann mit {{ whatever-object.whatever-property }} auf den Inhalt zu. Die Variable wird nicht aktualisiert, da JavaScript Primitive Typ nach Wert durchläuft. Während Objekt werden von Referenz übergeben was das Problem löst.

0
Yohe