Render value without data-binding

49,506

Solution 1

Angular 1.3+

In 1.3, Angular has supported this using the following syntax.

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

As mentioned in this answer.


Angular 1.2 and below

This is simple and doesn't need a plugin. Check this out.

This small directive will easily accomplish what you are trying to achieve

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

You can bind once like this

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

You can bind like normal

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

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

Some of you may be using angular batarang, and as mentioned in the comments if you use this directive the element still shows as binding when it is not, I am pretty sure this has something to do with the classes that are attached to the element so try this, it should work (not tested). Let me know in the comments if it worked for you.

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

@x0b: If you have OCD and you want to remove the empty class attribute do this

!$element.attr('class') && $element.removeAttr('class')

Solution 2

It looks like Angular 1.3 (starting with beta 10) has one-time binding built in:

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

One-time binding

An expression that starts with :: is considered a one-time expression. One-time expressions will stop recalculating once they are stable, which happens after the first digest if the expression result is a non-undefined value (see value stabilization algorithm below).

Solution 3

Use the bindonce module. You'll need to include the JS file and add it as a dependency to your app module:

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

This library allows you to render items that are bound only once — when they are first initialized. Any further updates to those values will be ignored. It's a great way to reduce the number of watches on the page for things that won't change after they are rendered.

Usage example:

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

When used like this, the property under value will be set once it is available, but then the watch will be disabled.

Solution 4

Comparison between @OverZealous and @Connor answers :

With the traditional ngRepeat of angular : 15s for 2000 rows and 420mo of RAM (Plunker)

With ngRepeat and the module of @OverZealous : 7s for 2000 rows and 240mo of RAM(Plunker)

With ngRepeat and the directive of @Connor : 8s for 2000 rows and 500mo of RAM (Plunker)

I made my tests with Google Chrome 32.

Solution 5

As an alternative, there is angular-once package:

If you use AngularJS, have performance issues and need to display lots of readonly data, this project is for you!

angular-once was actually inspired by bindonce and provides similar once-* attributes:

<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>
Share:
49,506
Blowsie
Author by

Blowsie

I'm an enthusiastic freelance designer and coder based in the United Kingdom. Key web based skills: Prototyping Coding Cross-browser Support Mobile Interfaces Testing Search Engine Optimisation Social Media Email Marketing HTML Semantics

Updated on July 08, 2022

Comments

  • Blowsie
    Blowsie almost 2 years

    In AngularJS, how can I render a value without 2-way data binding? One may want to do this for performance reasons, or even rendering a value at a given point in time.

    The following examples both use data binding:

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

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

    How do I render value without any data binding?

  • Mark Rajcok
    Mark Rajcok over 10 years
    I was about to write an answer "write your own directive ...", but it looks like someone has already done that for us, nice.
  • OverZealous
    OverZealous over 10 years
    Bindonce is useful enough that it could be included as a built-in optional library, like $resource.
  • Blowsie
    Blowsie over 10 years
    this is what i was looking for, however I was expecting something like this to be built into angular!
  • Blowsie
    Blowsie over 10 years
    im yet to test the plugin, but I would assume the AngularJS chrome tools would not show the bind-once element as a binding, where as your example does. Interesting approach tho, I will test both approaches soon.
  • Blowsie
    Blowsie over 10 years
  • iConnor
    iConnor over 10 years
    Without a doubt that is because if the ng-binding class that you can easily remove
  • iConnor
    iConnor over 10 years
    In the setTimeout remove the ng-binding and ng-scope classes
  • Yaron
    Yaron over 10 years
    This is great and much simpler than the bindonce plugin. I added an ability to wait for a condition before destroying the scope and it's really helpful. thanks.
  • Robert Koritnik
    Robert Koritnik over 10 years
    Wouldn't it be better to use $timeout to make it testable?
  • iConnor
    iConnor over 10 years
    @RobertKoritnik I can't see any advantages using $timeout, it will be doing more operations that I don't think are needed, of course you can do though, if you wish
  • x0b
    x0b about 10 years
    For those who want to remove a redundant empty class attribute then add this: if ($element.attr('class') === '') { $element.removeAttr('class'); }
  • iConnor
    iConnor about 10 years
    @x0b cheers, I've done that before, it does get annoying I'll add a reference in the answer.
  • XDS
    XDS almost 10 years
    This answer again and again. I can't praise you enough Karl! I highly recommend the agressive usage of this feature wherever it makes sense.
  • JSager
    JSager almost 10 years
    Wow I am really glad I scrolled down. I'm going to ask Connor to reference this in his accepted answer.
  • Billy G
    Billy G almost 10 years
    I have a table / list with 2000 lines and using the one-time-binding operator my app gets extremely slow when first showing / rendering the list. So slow, that the browser asks me two or three times if I want to stop executing the script!
  • James Daily
    James Daily almost 10 years
    @billy-g Can you post a jsfiddle or plunker illustrating the issue?
  • Billy G
    Billy G almost 10 years
    @James Daily: Here is the "normal" case plnkr.co/edit/rCRP0T5fSgNIllx7F27y and here the "one-time expression" case plnkr.co/edit/Rd5VBVjkcX3sTJYGypUr but... I can not reproduce it there. Anyway, it isn't faster with the "one-time expression" and I have to do more investigation to find why it happens in my environment (I use 1.3 beta 18 of angularjs)
  • SirTophamHatt
    SirTophamHatt over 9 years
    How does this work for deferred objects on a scope? The bind-once is destroying the scope before the property I want to bind-once is resolved.
  • iConnor
    iConnor over 9 years
    @SirTophamHatt that defeats the object of "bind once", if your property isn't resolved then the first bound value will be undefined, you're going to need a different solution for a different problem
  • SirTophamHatt
    SirTophamHatt over 9 years
    @Connor I disagree. For example, I'm receiving a video object ($scope.video) from a REST API and I want one-time binding of the video title ($scope.video.title). Even if I resolve the promise BEFORE adding it to the scope in the controller, I still have to declare ng-bind="video.title" bind-once on the DOM. Now, before the promise gets resolved, video.title is undefined, and the scope gets destroyed before video.title is defined. A solution I have for this is to wrap the elements in some type of loading/init flag, ng-if="someLoadingFlag", but it's a poor pattern.
  • alecxe
    alecxe over 9 years
    Would be nice to also have angular-once compared. Thanks.
  • Gabriel
    Gabriel over 9 years
    @alecxe : I planned to do the tests when a stable build of AngularJS 1.3 be published.
  • alecxe
    alecxe over 9 years
    Thanks, don't forget to include angular-once package (I've posted it as an alternative option here).
  • Yaniv Efraim
    Yaniv Efraim over 9 years
    @Connor - the "$scope.$destroy" will not remove the $watch (on angular 1.2). Any ideas how this could be fixed? see stackoverflow.com/questions/27400422/…
  • Augustin Riedinger
    Augustin Riedinger almost 9 years
    After struggling for a while, I made a Question regarding the Batarang thing: stackoverflow.com/questions/32012004/…