Wert ohne Datenbindung rendern

87

Wie kann ich in AngularJS einen Wert ohne bidirektionale Datenbindung rendern? Möglicherweise möchten Sie dies aus Leistungsgründen tun oder sogar einen Wert zu einem bestimmten Zeitpunkt rendern.

In den folgenden Beispielen wird die Datenbindung verwendet:

<div>{{value}}</div>

<div data-ng-bind="value"></div>

Wie rendere ich value ohne Datenbindung?

Blowsie
quelle
Was ist Ihre Eingabe und Ausgabe. PLZ erklären
Nitish Kumar
3
Ihre Beispiele sind tatsächlich einseitige Datenbindungen (Modelländerungen -> Aktualisierungen anzeigen). ng-modelbietet Ihnen bidirektionale Datenbindung: Modelländerungen -> Aktualisierungen anzeigen, Änderungen anzeigen -> Modellaktualisierungen.
Mark Rajcok
1
Aktualisiert. Entschuldigung, ich meinte, ich möchte überhaupt keine Datenbindung
Blowsie
10
Ich denke nicht, dass diese Frage schrecklich ist oder eine Ablehnung verdient. Es ist eigentlich üblich, die Datenbindung zu deaktivieren, um unnötige Uhren zu vermeiden.
OverZealous
4
UPDATE: Jeder, der diesen Artikel liest, wird dieses Video wahrscheinlich äußerst nützlich finden. youtube.com/watch?v=zyYpHIOrk_Y
Blowsie

Antworten:

141

Winkel 1,3+

In 1.3 hat Angular dies mithilfe der folgenden Syntax unterstützt.

<div>{{::message}}</div>

Wie in dieser Antwort erwähnt .


Winkel 1.2 und darunter

Dies ist einfach und benötigt kein Plugin. Überprüfen Sie dies heraus.

Diese kleine Richtlinie wird leicht das erreichen, was Sie erreichen wollen

app.directive('bindOnce', function() {
    return {
        scope: true,
        link: function( $scope ) {
            setTimeout(function() {
                $scope.$destroy();
            }, 0);
        }
    }
});

Sie können einmal so binden

<div bind-once>I bind once - {{message}}</div>

Sie können wie gewohnt binden

<div ng-bind="message" bind-once></div>

Demo: http://jsfiddle.net/fffnb/

Einige von Ihnen verwenden möglicherweise eckigen Batarang, und wie in den Kommentaren erwähnt, wird das Element, wenn Sie diese Direktive verwenden, immer noch als verbindlich angezeigt, wenn dies nicht der Fall ist. Ich bin mir ziemlich sicher, dass dies etwas mit den Klassen zu tun hat, die an das Element angehängt sind Versuchen Sie dies, es sollte funktionieren (nicht getestet) . Lassen Sie mich in den Kommentaren wissen, ob es für Sie funktioniert hat.

app.directive('bindOnce', function() {
    return {
        scope: true,
        link: function( $scope, $element ) {
            setTimeout(function() {
                $scope.$destroy();
                $element.removeClass('ng-binding ng-scope');
            }, 0);
        }
    }
});

@ x0b : Wenn Sie eine Zwangsstörung haben und das leere classAttribut entfernen möchten, tun Sie dies

!$element.attr('class') && $element.removeAttr('class')
iConnor
quelle
Ich muss das Plugin noch testen, aber ich würde davon ausgehen, dass die AngularJS-Chrome-Tools das einmalige Bindeelement nicht als Bindung anzeigen, wie in Ihrem Beispiel. Interessanter Ansatz, ich werde beide Ansätze bald testen.
Blowsie
Sehen Sie dies - es zeigt beide als Bindungen dl.dropboxusercontent.com/u/14037764/Development/stackoverflow/…
Blowsie
1
Ohne Zweifel liegt das daran, dass wenn die ng-Bindungsklasse, die Sie leicht entfernen können
iConnor
4
Dies ist großartig und viel einfacher als das Bindonce-Plugin. Ich habe die Möglichkeit hinzugefügt, auf eine Bedingung zu warten, bevor das Zielfernrohr zerstört wird, und es ist wirklich hilfreich. Vielen Dank.
Yaron
1
@Connor Ich bin anderer Meinung. Beispielsweise erhalte ich ein Videoobjekt ($ scope.video) von einer REST-API und möchte den Videotitel ($ scope.video.title) einmalig binden. Selbst wenn ich das Versprechen auflöse, bevor ich es dem Bereich im Controller hinzufüge, muss ich ng-bind = "video.title" im DOM einmal deklarieren. Bevor das Versprechen aufgelöst wird, ist video.title undefiniert und der Bereich wird zerstört, bevor video.title definiert wird. Eine Lösung, die ich dafür habe, besteht darin, die Elemente in eine Art Lade- / Init-Flag zu verpacken, ng-if = "someLoadingFlag", aber es ist ein schlechtes Muster.
SirTophamHatt
49

Es sieht so aus, als ob Angular 1.3 (beginnend mit Beta 10) eine einmalige Bindung eingebaut hat:

https://docs.angularjs.org/guide/expression#one-time-binding

Einmalige Bindung

Ein Ausdruck, der mit :: beginnt, wird als einmaliger Ausdruck betrachtet. Einmalige Ausdrücke werden nicht mehr neu berechnet, sobald sie stabil sind. Dies geschieht nach dem ersten Digest, wenn das Ausdrucksergebnis ein nicht undefinierter Wert ist (siehe Wertstabilisierungsalgorithmus unten).

Karen Zilles
quelle
1
Diese Antwort immer wieder. Ich kann dich nicht genug loben Karl! Ich empfehle die aggressive Verwendung dieser Funktion, wo immer es sinnvoll ist.
XDS
1
Wow, ich bin wirklich froh, dass ich nach unten gescrollt habe. Ich werde Connor bitten, dies in seiner akzeptierten Antwort zu erwähnen.
JSager
Ich habe eine Tabelle / Liste mit 2000 Zeilen und mit dem einmaligen Bindungsoperator wird meine App beim ersten Anzeigen / Rendern der Liste extrem langsam. So langsam, dass der Browser mich zwei- oder dreimal fragt, ob ich die Ausführung des Skripts beenden möchte!
Billy G
@ billy-g Kannst du eine jsfiddle oder einen plunker posten, die das Problem veranschaulichen?
James Daily
@ James Daily: Hier ist der "normale" Fall plnkr.co/edit/rCRP0T5fSgNIllx7F27y und hier der Fall "einmaliger Ausdruck" plnkr.co/edit/Rd5VBVjkcX3sTJYGypUr, aber ... ich kann ihn dort nicht reproduzieren. Wie auch immer, es ist nicht schneller mit dem "einmaligen Ausdruck" und ich muss mehr Nachforschungen anstellen, um herauszufinden, warum es in meiner Umgebung passiert (ich verwende 1.3 Beta 18 von AngularJs)
Billy G
20

Verwenden Sie das Bindonce-Modul . Sie müssen die JS-Datei einschließen und als Abhängigkeit zu Ihrem App-Modul hinzufügen:

var myApp = angular.module("myApp", ['pasvaz.bindonce']);

Mit dieser Bibliothek können Sie Elemente rendern, die nur einmal gebunden sind - wenn sie zum ersten Mal initialisiert werden. Alle weiteren Aktualisierungen dieser Werte werden ignoriert. Dies ist eine großartige Möglichkeit, die Anzahl der Uhren auf der Seite für Dinge zu reduzieren, die sich nach dem Rendern nicht ändern.

Anwendungsbeispiel:

<div bo-text="value"></div>

Bei einer solchen Verwendung wird die Eigenschaft unter valuefestgelegt, sobald sie verfügbar ist. Anschließend wird die Uhr deaktiviert.

Übereifrig
quelle
1
Ich wollte gerade eine Antwort schreiben "Schreibe deine eigene Anweisung ...", aber es sieht so aus, als hätte das schon jemand für uns getan, nett.
Mark Rajcok
3
Bindonce ist so nützlich, dass es als integrierte optionale Bibliothek enthalten sein kann, wie z $resource.
OverZealous
6
das ist, wonach ich gesucht habe, aber ich hatte erwartet, dass so etwas in Winkel eingebaut wird!
Blowsie
7

Vergleich zwischen @OverZealous und @Connor Antworten:

Mit dem traditionellen ngRepeat von Angular: 15s für 2000 Zeilen und 420mo RAM ( Plunker )

Mit ngRepeat und dem Modul von @OverZealous: 7s für 2000 Zeilen und 240Mo RAM ( Plunker )

Mit ngRepeat und der Direktive von @Connor: 8s für 2000 Zeilen und 500Mo RAM ( Plunker )

Ich habe meine Tests mit Google Chrome 32 durchgeführt.

Gabriel
quelle
1
Wäre schön auch angular-onceverglichen zu haben . Vielen Dank.
Alecxe
@alecxe: Ich hatte vor, die Tests durchzuführen, wenn ein stabiler Build von AngularJS 1.3 veröffentlicht wird.
Gabriel
Vielen Dank, vergessen Sie nicht, das angular-oncePaket beizufügen (ich habe es hier als alternative Option veröffentlicht).
Alecxe
5

Als Alternative gibt es angular-oncePaket:

Wenn Sie AngularJS verwenden, Leistungsprobleme haben und viele schreibgeschützte Daten anzeigen müssen, ist dieses Projekt genau das Richtige für Sie!

angular-oncewurde tatsächlich inspiriert bindonceund bietet ähnliche once-*Attribute:

<ul>
    <li ng-repeat="user in users">
      <a once-href="user.profileUrl" once-text="user.name"></a>
        <a once-href="user.profileUrl"><img once-src="user.avatarUrl"></a>
        <div once-class="{'formatted': user.description}" once-bind="user.description"></div>
    </li>
</ul>
Alecxe
quelle