86

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?

6
  • whats your input and output . plz explain Commented Sep 13, 2013 at 15:52
  • 3
    Your examples are actually one-way data binding (model changes -> view updates). ng-model gives you two-way data binding: model changes -> view updates, view changes -> model updates. Commented Sep 13, 2013 at 15:55
  • 1
    updated. sorry i meant I want no data-binding at all Commented Sep 13, 2013 at 16:01
  • 10
    I don't think this question is terrible or deserved a downvote. It's actually really common to want to disable data binding to prevent unnecessary watches. Commented Sep 13, 2013 at 16:01
  • 4
    UPDATE: anyone reading this article will probaly find this video extremely useful. youtube.com/watch?v=zyYpHIOrk_Y Commented Jan 24, 2014 at 12:24

5 Answers 5

139

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')
Sign up to request clarification or add additional context in comments.

14 Comments

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.
Without a doubt that is because if the ng-binding class that you can easily remove
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.
@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.
|
49

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).

5 Comments

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.
Wow I am really glad I scrolled down. I'm going to ask Connor to reference this in his accepted answer.
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!
@billy-g Can you post a jsfiddle or plunker illustrating the issue?
@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)
20

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.

3 Comments

I was about to write an answer "write your own directive ...", but it looks like someone has already done that for us, nice.
Bindonce is useful enough that it could be included as a built-in optional library, like $resource.
this is what i was looking for, however I was expecting something like this to be built into angular!
7

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.

3 Comments

Would be nice to also have angular-once compared. Thanks.
@alecxe : I planned to do the tests when a stable build of AngularJS 1.3 be published.
Thanks, don't forget to include angular-once package (I've posted it as an alternative option here).
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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.