New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

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

Comments

Projects
None yet
8 participants
@david-hollifield

david-hollifield commented Sep 23, 2014

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

david-hollifield commented Sep 23, 2014

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

@knalli

This comment has been minimized.

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

This comment has been minimized.

david-hollifield commented Sep 23, 2014

Thanks! Gotcha.

@knalli

This comment has been minimized.

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.

@knalli knalli closed this Sep 23, 2014

@knalli knalli added the question label Sep 23, 2014

@ajwhite

This comment has been minimized.

ajwhite 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

This comment has been minimized.

david-hollifield commented Jun 2, 2015

@ajwhite Nice!

@JerryBels

This comment has been minimized.

JerryBels commented Aug 13, 2015

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

This comment has been minimized.

JerryBels commented Aug 16, 2015

@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 ?

@ajwhite

This comment has been minimized.

ajwhite commented Aug 16, 2015

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

This comment has been minimized.

JerryBels commented Aug 17, 2015

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 :/

@ajwhite

This comment has been minimized.

ajwhite commented Aug 17, 2015

@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

This comment has been minimized.

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

This comment has been minimized.

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>

@ajwhite

This comment has been minimized.

ajwhite commented Jun 24, 2016

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

This comment has been minimized.

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

This comment has been minimized.

Contributor

lopesc commented Jul 25, 2016

@bmhumadi

This comment has been minimized.

bmhumadi commented May 15, 2018

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 join this conversation on GitHub. Already have an account? Sign in to comment