Skip to content
This repository has been archived by the owner on Jan 29, 2024. It is now read-only.
This repository has been archived by the owner on Jan 29, 2024. It is now read-only.

One-time Binding in angularjs 1.3.0.-rc2 #738

Closed
david-hollifield opened this issue Sep 23, 2014 · 19 comments
Closed

One-time Binding in angularjs 1.3.0.-rc2 #738

david-hollifield opened this issue Sep 23, 2014 · 19 comments

Comments

@david-hollifield
Copy link

If I use angular's new one-time binding syntax on my translated values, shouldn't the watch be removed after the translate value is defined?

I use something like <h3>{{::'FeaturedProducts' | translate}}</h3>, but I still see a watch in Batarang.

I'm not sure if this is a bug in angular, angular-translate, or my misunderstanding of how the on-time binding should work, but this seems like a perfect scenario to use the one-time binding feature.

BTW, I'm using latest 2.4.0 of angular-translate

@knalli
Copy link
Member

knalli commented Sep 23, 2014

The filter itself is being marked as $stateful, perhaps that's a cause? We should dig into the internals to look for this...

@knalli
Copy link
Member

knalli commented Sep 23, 2014

I want to highlight one aspect

I'm not sure if this is a bug in angular, angular-translate, or my misunderstanding of how the on-time binding should work, but this seems like a perfect scenario to use the one-time binding feature.

No, actually it is not. Filters are invoked by AJS and several points in your lifetime. Some of these invocations are at the start of the application when no (correct) translations are available. And some of them will be invoked with the correct language (i.e. templates built after events or other data available).

And at top of this, I'm naming partial translations (loaded via XHR), fallback languages or even refreshes.

@david-hollifield
Copy link
Author

I'm not sure I understand what you're saying. Should I not be trying to use onetime binding for my translated strings?

@knalli
Copy link
Member

knalli commented Sep 23, 2014

It depends.

The idea of one time binding in scope of AJS expressions is they

will stop recalculating once they are stable, which happens after the first digest if the expression result is a non-undefined value (link)

This requires the translation will only return a non-undefined value in case of success, but only undefined values for fails (these means: no default text, no fallback links, no placeholders, and so on).

You can (should?) configure angular_translate this way, however, I'm quite not sure you really want this. IMHO(!): You are wasting your time to optimize these watches, that should not have such an impact (-> Rules Of Optimization). We are (and I am especially) welcome for every information speaking of runtime performance, but as far as I know/do it works very snappy with dozens of filters.

One of the reasons why the filter is explicitly marked as $stateful (since 2.4) because we need exactly the removed feature (see https://github.com/angular/angular.js/blob/729c238e19ab27deff01448d79342ea53721bfed/docs/content/guide/filter.ngdoc#L130-L138). The translate filter is not a simple pure function, because it relies on the current active language and the current active translations. Using a pure filter, everybody would have to write for every filter something like {{ <h3>{{::'FeaturedProducts' | translate: {language:currentLanguage, allTranslations: allTranslations} }}</h3> }} -- and if params are in the string, the scope/this must be applied, too.

@david-hollifield
Copy link
Author

Thanks! Gotcha.

@knalli
Copy link
Member

knalli commented Sep 23, 2014

Nice to hear.

If someone can improve this process, we are welcome for ideas. Always.

So far, I'm closing this.

@atticoos
Copy link

atticoos commented Jun 2, 2015

Just happened to come across this. I've been working on a solution for one-time binding the translations with an extension to pascalprecht.translate, https://github.com/ajwhite/angular-translate-once

More on how it works: http://atticuswhite.com/blog/angularjs-translate-once-angular-translate-one-time-binding/

@david-hollifield
Copy link
Author

@ajwhite Nice!

@JerryBels
Copy link

For now I simply define my translations in the controller using $translate service, and then use a regular one time binding :: in the view. I guess it's the best I can do until angular-translate adds the :: functionnality to its filter and such ?

I don't really want to use your extension, @ajwhite , because I don't want to have to define an HTML element for every piece of text I want translated, since I actually rely heavily on the translate filter :/

@JerryBels
Copy link

@ajwhite actually, a question : do you think the performance gain worth installing your extension and adding elements to bind translations to ? Wouldn't the HTML be more heavy, so this nullify the improvement ?

@atticoos
Copy link

Great question @JerryBels. I'd be quite interested in doing some performance tests on that theory. It may add to the initial phase of constructing the DOM, but I can't say for sure how much overhead it will add.

Would be interesting to do a test with 100, 1,000, and 10,000 elements versus filters, invoke a few digest cycles, and see how things look

@JerryBels
Copy link

Hey @ajwhite, thanks for answering :) Are you planning to run these tests ? If so, I would be very interested if you could give your conclusions here whenever it's done !

I must say I don't really know how to run that kind of tests myself :/

@atticoos
Copy link

@JerryBels -- probably not for a little while. I welcome you to submit an issue and either myself or a member from the community will pick it up at some point :)

@tangorri
Copy link

tangorri commented Apr 4, 2016

Hi,
using ::oneTimeBinding.
I meet the same problem, on certain rare circonstances the app fails to translate key (because of asynch loader). I agree I should have think about it, but it should be indicated as 'dangerous' in documentation. Removing watchers is usefull because we can use directive in massive repeated loop...

@mebibou
Copy link

mebibou commented Jun 24, 2016

Would this work <h3>{{::value = ('FeaturedProducts' | translate)}}</h3>? I haven't tried though

Or maybe an uglier version if it doesn't cut it: <h3 ng-init="value = ('FeaturedProducts' | translate)">{{::value}}</h3>

@atticoos
Copy link

No - the filter can still return the undesired value. The localization files are not loaded synchronously, so there is no guarantee that they will be available of a onetime binding is used.

@lopesc
Copy link
Contributor

lopesc commented Jul 25, 2016

Is there any advantage to using this: <span translate = "{{::'KEY'}}"></span>. I assume that just the bit inside the double quotes "{{::'KEY'}}" will be removed from the watcher (since it is an expression). This will resolve to just "KEY", and the directive itself will still be watching that attribute - Therefore for one to use a bind-once-and-forget approach, they would be limited to the filter only.

@lopesc
Copy link
Contributor

lopesc commented Jul 25, 2016

@PascalPrecht @knalli

@bmhumadi
Copy link

I was able to use one-time binding without any library like bind-once
<span translate="play"></span>
to
<span>{{:: 'play' | translate }}</span>

I hope this helps others. It took me hours to find this solution

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants