Отображать значение без привязки данных

87

Как в AngularJS отобразить значение без двусторонней привязки данных? Это может потребоваться из соображений производительности или даже для визуализации значения в заданный момент времени.

В следующих примерах используется привязка данных:

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

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

Как выполнить рендеринг value без привязки данных?

Blowsie
источник
каков ваш ввод и вывод. пожалуйста, объясните
Нитиш Кумар
3
Ваши примеры на самом деле являются односторонней привязкой данных (изменения модели -> просмотр обновлений). ng-modelдает вам двустороннюю привязку данных: изменения модели -> просмотр обновлений, просмотр изменений -> обновления модели.
Марк Райкок
1
обновлено. извините, я имел в виду, что не хочу никакой привязки данных вообще
Blowsie
10
Я не думаю, что этот вопрос ужасен или заслуживает отрицательной оценки. На самом деле очень часто хочется отключить привязку данных, чтобы предотвратить ненужные наблюдения.
OverZealous
4
ОБНОВЛЕНИЕ: любой, кто читает эту статью, вероятно, найдет это видео чрезвычайно полезным. youtube.com/watch?v=zyYpHIOrk_Y
Blowsie

Ответы:

141

Угловой 1.3+

В версии 1.3 Angular поддерживал это, используя следующий синтаксис.

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

Как упоминалось в этом ответе .


Angular 1.2 и ниже

Это просто и не требует плагина. Проверь это.

Эта небольшая директива легко выполнит то, что вы пытаетесь достичь.

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

Вы можете привязать один раз вот так

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

Вы можете связать как обычно

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

Демо: http://jsfiddle.net/fffnb/

Некоторые из вас могут использовать angular batarang, и, как упоминалось в комментариях, если вы используете эту директиву, элемент по-прежнему отображается как привязка, когда это не так, я почти уверен, что это как-то связано с классами, которые прикреплены к элементу, поэтому попробуйте это, он должен работать (не проверено) . Дайте мне знать в комментариях, если это сработало для вас.

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

@ x0b : если у вас ОКР и вы хотите удалить пустой classатрибут, сделайте это

!$element.attr('class') && $element.removeAttr('class')
iConnor
источник
Я еще не тестировал плагин, но я бы предположил, что инструменты Chrome AngularJS не будут отображать элемент bind-once как привязку, где, как это делает ваш пример. Интересный подход, но скоро я опробую оба подхода.
Blowsie
См. Это - он показывает оба как привязки dl.dropboxusercontent.com/u/14037764/Development/stackoverflow/…
Blowsie
1
Без сомнения, это потому, что если класс ng-binding, который вы можете легко удалить
iConnor
4
Это здорово и намного проще, чем плагин bindonce. Я добавил возможность дождаться состояния, прежде чем уничтожить прицел, и это действительно полезно. Спасибо.
Yaron
1
@ Коннор Я не согласен. Например, я получаю видеообъект ($ scope.video) из REST API и хочу одноразовую привязку заголовка видео ($ scope.video.title). Даже если я разрешаю обещание ПЕРЕД добавлением его в область видимости в контроллере, мне все равно придется объявить ng-bind = "video.title" bind-once в DOM. Теперь, прежде чем обещание будет разрешено, video.title не определено, а область видимости будет уничтожена до определения video.title. У меня есть решение для этого - заключить элементы в какой-то тип флага загрузки / инициализации, ng-if = "someLoadingFlag", но это плохой шаблон.
SirTophamHatt
49

Похоже, что в Angular 1.3 (начиная с beta 10) встроена одноразовая привязка:

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

Одноразовая привязка

Выражение, которое начинается с ::, считается одноразовым выражением. Одноразовые выражения перестанут пересчитываться, как только они станут стабильными, что происходит после первого дайджеста, если результатом выражения является не неопределенное значение (см. Алгоритм стабилизации значения ниже).

Карен Зиллес
источник
1
Этот ответ снова и снова. Я не могу достаточно хвалить тебя, Карл! Я настоятельно рекомендую активно использовать эту функцию везде, где это имеет смысл.
XDS
1
Вау, я действительно рад, что прокрутил страницу вниз. Я попрошу Коннора упомянуть об этом в принятом ответе.
JSager
У меня есть таблица / список с 2000 строками, и с использованием оператора одноразовой привязки мое приложение становится очень медленным при первом отображении / рендеринге списка. Настолько медленно, что браузер два или три раза спрашивает меня, хочу ли я прекратить выполнение скрипта!
Billy G
@ billy-g Можете ли вы опубликовать jsfiddle или plunker, иллюстрирующие проблему?
Джеймс Дейли,
@James Daily: Вот "нормальный" случай plnkr.co/edit/rCRP0T5fSgNIllx7F27y, а здесь случай "одноразового выражения" plnkr.co/edit/Rd5VBVjkcX3sTJYGypUr, но ... я не могу воспроизвести его там. В любом случае, это не быстрее с «одноразовым выражением», и мне нужно провести дополнительное исследование, чтобы выяснить, почему это происходит в моей среде (я использую 1.3 beta 18 angularjs)
Билли Джи
20

Используйте модуль bindonce . Вам нужно будет включить JS-файл и добавить его как зависимость к вашему модулю приложения:

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

Эта библиотека позволяет отображать элементы, которые связаны только один раз - при их первой инициализации. Любые дальнейшие обновления этих значений будут проигнорированы. Это отличный способ уменьшить количество отслеживаний на странице вещей, которые не изменятся после рендеринга.

Пример использования:

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

При таком использовании свойство ниже valueбудет установлено, как только оно станет доступным, но затем часы будут отключены.

Чрезмерно рьяный
источник
1
Я собирался написать ответ «напишите свою директиву ...», но похоже, что кто-то уже сделал это за нас, приятно.
Марк Райкок
3
Bindonce достаточно полезен, чтобы его можно было включить как встроенную дополнительную библиотеку, например $resource.
OverZealous
6
это то, что я искал, однако я ожидал, что что-то подобное будет встроено в angular!
Blowsie
7

Сравнение ответов @OverZealous и @Connor:

С традиционным ngRepeat angular: 15 с для 2000 строк и 420 МБ ОЗУ ( Plunker )

С ngRepeat и модулем @OverZealous: 7 с для 2000 строк и 240 млн ОЗУ ( Plunker )

С ngRepeat и директивой @Connor: 8s для 2000 строк и 500mo RAM ( Plunker )

Я провел свои тесты с Google Chrome 32.

Габриэль
источник
1
Было бы неплохо тоже angular-onceсравнить. Спасибо.
alecxe
@alecxe: Я планировал провести тесты, когда будет опубликована стабильная сборка AngularJS 1.3.
Габриэль
Спасибо, не забудьте включить angular-onceпакет (я разместил его здесь как альтернативный вариант).
alecxe
5

В качестве альтернативы есть angular-onceпакет:

Если вы используете AngularJS, имеете проблемы с производительностью и вам нужно отображать много данных только для чтения, этот проект для вас!

angular-onceбыл фактически вдохновлен bindonceи предоставляет похожие once-*атрибуты:

<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>
алексе
источник