Wartość renderowania bez wiązania danych

87

W AngularJS, jak mogę renderować wartość bez dwukierunkowego wiązania danych? Można to zrobić ze względu na wydajność, a nawet renderowanie wartości w danym momencie.

Poniższe przykłady używają powiązania danych:

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

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

Jak renderować value bez powiązania danych?

Blowsie
źródło
jakie masz dane wejściowe i wyjściowe. plz wyjaśnij
Nitish Kumar
3
Twoje przykłady to w rzeczywistości jednokierunkowe powiązanie danych (zmiany modelu -> aktualizacje widoku). ng-modelzapewnia dwukierunkowe powiązanie danych: zmiany modelu -> wyświetl aktualizacje, wyświetl zmiany -> aktualizacje modelu.
Mark Rajcok
1
zaktualizowany. przepraszam, chodziło mi o to, że wcale nie chcę wiązać danych
Blowsie
10
Nie sądzę, aby to pytanie było straszne lub zasługiwało na negatywną opinię. W rzeczywistości bardzo powszechne jest wyłączenie wiązania danych, aby zapobiec niepotrzebnym zegarkom.
OverZealous
4
AKTUALIZACJA: każdy, kto czyta ten artykuł, prawdopodobnie uzna ten film za niezwykle przydatny. youtube.com/watch?v=zyYpHIOrk_Y
Blowsie

Odpowiedzi:

141

Angular 1.3+

W wersji 1.3 Angular obsługiwał to przy użyciu następującej składni.

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

Jak wspomniano w tej odpowiedzi .


Kątowy 1.2 i niższy

Jest to proste i nie wymaga wtyczki. Sprawdź to.

Ta niewielka dyrektywa z łatwością osiągnie to, co próbujesz osiągnąć

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

Możesz raz związać się w ten sposób

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

Możesz wiązać jak zwykle

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

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

Niektórzy z was mogą używać kątowego batarangu i jak wspomniano w komentarzach, jeśli używasz tej dyrektywy, element nadal wyświetla się jako wiążący, gdy nie jest, jestem prawie pewien, że ma to coś wspólnego z klasami, które są dołączone do elementu, więc spróbuj tego, powinno działać (nie testowane) . Daj mi znać w komentarzach, czy to zadziałało.

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

@ x0b : Jeśli masz OCD i chcesz usunąć pusty classatrybut, zrób to

!$element.attr('class') && $element.removeAttr('class')
iConnor
źródło
Jeszcze nie przetestowałem wtyczki, ale zakładam, że narzędzia Chrome AngularJS nie pokażą elementu bind-once jako powiązania, gdzie tak jak w twoim przykładzie. Ciekawe podejście, ale wkrótce przetestuję oba podejścia.
Blowsie
Zobacz to - pokazuje oba jako wiązania dl.dropboxusercontent.com/u/14037764/Development/stackoverflow/ ...
Blowsie
1
Bez wątpienia
dzieje się
4
Jest to świetne i znacznie prostsze niż wtyczka bindonce. Dodałem możliwość czekania na stan przed zniszczeniem lunety i jest to naprawdę pomocne. dzięki.
Yaron,
1
@Connor Nie zgadzam się. Na przykład odbieram obiekt wideo ($ scope.video) z REST API i chcę jednorazowo powiązać tytuł wideo ($ scope.video.title). Nawet jeśli spełnię obietnicę PRZED dodaniem jej do zakresu w kontrolerze, nadal muszę zadeklarować ng-bind = "video.title" bind-once w DOM. Teraz, zanim obietnica zostanie spełniona, video.title jest niezdefiniowane, a zakres zostaje zniszczony przed zdefiniowaniem video.title. Rozwiązaniem, które mam na to, jest zawinięcie elementów w jakąś flagę ładowania / inicjalizacji, ng-if = "someLoadingFlag", ale jest to kiepski wzorzec.
SirTophamHatt
49

Wygląda na to, że Angular 1.3 (zaczynając od beta 10) ma wbudowane jednorazowe powiązanie:

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

Jednorazowe wiązanie

Wyrażenie zaczynające się od :: jest uważane za wyrażenie jednorazowe. Wyrażenia jednorazowe przestaną się ponownie obliczać, gdy staną się stabilne, co ma miejsce po pierwszym podsumowaniu, jeśli wynik wyrażenia jest wartością nieokreśloną (patrz algorytm stabilizacji wartości poniżej).

Karen Zilles
źródło
1
Ta odpowiedź wciąż i znowu. Nie mogę cię wystarczająco pochwalić Karl! Gorąco polecam agresywne korzystanie z tej funkcji wszędzie tam, gdzie ma to sens.
XDS,
1
Wow, naprawdę się cieszę, że przewinęłam stronę. Poproszę Connora, aby odniósł się do tego w zaakceptowanej odpowiedzi.
JSager,
Mam tabelę / listę z 2000 wierszami i używając operatora jednorazowego wiązania, moja aplikacja działa bardzo wolno podczas pierwszego wyświetlania / renderowania listy. Tak wolno, że przeglądarka pyta mnie dwa lub trzy razy, czy chcę zatrzymać wykonywanie skryptu!
Billy G
@ billy-g Czy możesz opublikować plik jsfiddle lub plunker ilustrujący problem?
James Daily,
@James Daily: Oto "normalna" sprawa plnkr.co/edit/rCRP0T5fSgNIllx7F27y, a tutaj przypadek "jednorazowego wyrażenia" plnkr.co/edit/Rd5VBVjkcX3sTJYGypUr, ale ... nie mogę tego odtworzyć. W każdym razie, nie jest to szybsze z „jednorazowym wyrażeniem” i muszę dokładniej zbadać, dlaczego tak się dzieje w moim środowisku (używam 1.3 beta 18 angularjs)
Billy G
20

Użyj modułu bindonce . Musisz dołączyć plik JS i dodać go jako zależność do modułu aplikacji:

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

Ta biblioteka umożliwia renderowanie elementów, które są powiązane tylko raz - podczas pierwszej inicjalizacji. Wszelkie dalsze aktualizacje tych wartości będą ignorowane. To świetny sposób na zmniejszenie liczby obserwowanych na stronie elementów, które nie ulegną zmianie po wyrenderowaniu.

Przykład użycia:

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

W takim przypadku właściwość poniżej valuezostanie ustawiona, gdy będzie dostępna, ale wtedy zegarek zostanie wyłączony.

OverZealous
źródło
1
Miałem właśnie napisać odpowiedź „napisz własną dyrektywę…”, ale wygląda na to, że ktoś już to dla nas zrobił, fajnie.
Mark Rajcok
3
Bindonce jest na tyle użyteczne, że można by je dołączyć jako wbudowaną bibliotekę opcjonalną, taką jak $resource.
OverZealous
6
to jest to, czego szukałem, jednak spodziewałem się, że coś takiego zostanie wbudowane w kanciaste!
Blowsie
7

Porównanie odpowiedzi @OverZealous i @Connor:

Z tradycyjnym ngRepeat of angular: 15s dla 2000 rzędów i 420mo pamięci RAM ( Plunker )

Z ngRepeat i modułem @OverZealous: 7s dla 2000 wierszy i 240mo pamięci RAM ( Plunker )

Z ngRepeat i dyrektywą @Connor: 8s dla 2000 wierszy i 500mo pamięci RAM ( Plunker )

Przeprowadziłem testy w Google Chrome 32.

Gabriel
źródło
1
Byłoby miło również to angular-onceporównać. Dzięki.
alecxe
@alecxe: Planowałem przeprowadzić testy, gdy zostanie opublikowana stabilna wersja AngularJS 1.3.
Gabriel
Dzięki, nie zapomnij dołączyć angular-oncepakietu (zamieściłem go tutaj jako alternatywną opcję).
alecxe
5

Jako alternatywę dostępny jest angular-oncepakiet:

Jeśli używasz AngularJS, masz problemy z wydajnością i potrzebujesz wyświetlać dużo danych tylko do odczytu, ten projekt jest dla Ciebie!

angular-oncezostał zainspirowany bindoncei zapewnia podobne once-*cechy:

<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
źródło