Space Monkey
Space Monkey

Reputation: 1041

Update observable array property when a different observable is changed

I have a "locale" observable that is basically just a JS object that contains locale-specific strings. I also have a tabs observable array, which contains multiple properties, one of which is a title that is populated by a locale value.

e.g.

this.tabs = ko.observableArray([{
    title: this.locale().tabs.one
}, {
    title: this.locale().tabs.two
}]);

Here is a JSFiddle to demonstrate: http://jsfiddle.net/robgallen/v64p2/

I am trying to figure out the best strategy to get the tab titles to change when the locale observable is changed.

I have tried using knockout mapping but this doesn't seem to help. I have also tried adding a ko.observableArray.fn.refresh to update the data within the tabs array, but it simply uses the original tabs data, rather than referring back to the locale data.

Upvotes: 0

Views: 508

Answers (4)

Space Monkey
Space Monkey

Reputation: 1041

After thinking about the answers here, particularly Chuck's, this is about the best I could come up with:

http://jsfiddle.net/robgallen/v64p2/3/

Adding a subscription that re-populates the tabs array, using a key to lookup the changed locale string:

self.locale.subscribe(function (data) {
    var newTabs = [];
    ko.utils.arrayForEach(self.tabs(), function(tab) {
        tab.title = data.tabs[tab.key];
        newTabs.push(tab);
    });
    self.tabs(null);
    self.tabs(newTabs);
});

Not great and I realise I might not be thinking about this in the correct manner. Luckily most of the localisation is done in the html view and this works fine.

Upvotes: 0

user3174746
user3174746

Reputation:

Your best bet would be to use a client-side i18n solution such as i18next. The problem with allowing a user to dynamically change the locale is that it will lead to an enormously complex UI. Text that would otherwise be boilerplate--for example, field labels, tabs, etc.--would need to be observable in order to respond to an observable change in your locale (most likely in a configuration module). That configurable observable would have to be injected into every module in order to drive the observable changes in locale.

We tried the approach you're taking and found that it weighed us down burdensomely. We opted for something unobtrusive, something that didn't require observables everywhere just for the sake of conveying a language change.

@rwisch45 suggests subscribe, which will work--and work well--for a small solution. But subscribe won't scale well.

Upvotes: 1

Chuck Schneider
Chuck Schneider

Reputation: 344

How about this instead? updated fiddle

<ul data-bind="with: locale">
     <li data-bind="text: tabs.one"></li>
    <li data-bind="text: tabs.two"></li>
</ul>

Or this update to rwisch45's fiddle works too

Upvotes: 1

rwisch45
rwisch45

Reputation: 3702

You could use subscribe (see explicitly subscribing to observables in the KO docs) to know whenever the value of the locale has changed. See updated fiddle. The following observable subscription in your view model will fire off every time that the value of locale is changed. You can put your own custom logic inside the function.

self.locale.subscribe(function(){
   alert('locale changed');
});

Upvotes: 0

Related Questions