rivets icon indicating copy to clipboard operation
rivets copied to clipboard

force formatter recomputation

Open rogierslag opened this issue 9 years ago • 4 comments

We are running into a small problem with rivets. Our webapp is localizable, for this we use the formatters to display specific things in the correct format (dates / currencies etc). However, we want the user to be able to dynamically change the locale.

To prevent a complete reload, we should recompute all formatters. However, this is extremely ugly to do like this value | formatter < App.user.get('locale') everywhere. So we'd like to bind this to the formatter such that the formatter recomputes its value if the value changes. That way, we can still use the value | formatter syntax, but do not have to include the App.user.get('locale') everywhere, but can bind it directly to the formatter globally.

Is anything like this possible in rivets?

rogierslag avatar Feb 06 '15 14:02 rogierslag

This does also not work btw {{ 'Next' < App.i18n.initialized | i18n }} since it only allows binding to subparameters

rogierslag avatar Feb 06 '15 15:02 rogierslag

@rogierslag One way to do this would be to have your i18n formatter accept another argument for the locale you want to use. For example, if your formatter is implemented like this:

rivets.formatters.i18n = function(key, locale) {
  // return the translated text for key in locale
}

Then you can use it like this in your templates:

<button>{ 'Next' | i18n 'en' }</button>

To make the 'en' part dynamic, you can pass in a keypath here. So if you pass in the App.i18n object when binding your view, you can use it in place of the 'en' string litteral:

rivets.bind(el, {locales: App.i18n})
<button>{ 'Next' | i18n locales.initialized }</button>

Further, if you want to be able to reference this in any view without passing it into rivets.bind every time, then you can for example, create a read-only adapter to access properties on your global App object.

rivets.adapters['$'] = {
  get: function() {
    return App
  },
  set: function() {},
  observe: function() {},
  unobserve: function() {}
}

And then within any template:

<button>{ 'Next' | i18n $.i18n.initialized }</button>

Now when you set App.i18n.initialized = 'es', your view(s) should update themselves.

mikeric avatar Feb 08 '15 00:02 mikeric

This still does not work. Could you give an example where "recompute" happens when the argument to the formatter gets updated somewhere else in the document?

My ugly code: http://codepen.io/anon/pen/doZrxN which didn't work while trying to do what you said.

mkagenius avatar Jun 25 '15 15:06 mkagenius

We ended up by making the entire thing dependent on $ eg 'example test' | i18n < $ to prevent many boilerplate code in the test just to make it dynamic (in this case we featured clarity over consistency, since adding the parameter everytime to the formatter makes the code much harder to read)

rogierslag avatar Jun 25 '15 20:06 rogierslag