1

I've looked at this: http://knockoutjs.com/documentation/extenders.html

The issue is that I'm using fromJs to create my view model, so my observerables already exist. I would think I could do the following to add an extender:

var data = result.Data;
if (!window.vmRealTimeActivity) {
    window.vmRealTimeActivity = ko.mapping.fromJS(data, mappingKeys);
    ko.applyBindings(vmRealTimeActivity, $('#second-btm')[0]);
} else {
    ko.mapping.fromJS(data, vmRealTimeActivity);
}

vmRealTimeActivity.MyExistingObservable.extend({ numeric: null });
vmRealTimeActivity.MyExistingObservable(9999);  // doesn't call numeric extender

My extender gets called the first time the extender is attached, but not after trying to change the value.

I read another SO post that stated that .extend() creates a new observerable so you have to do this, but this doesn't work either:

vmRealTimeActivity.MyExistingObservable = vmRealTimeActivity.MyExistingObservable.extend({ numeric: null });

In addition to not calling my formatter a second time, the value starts coming back NaN.

How do I attach an extender the proper way to an existing observable?

KingOfHypocrites
  • 9,316
  • 9
  • 47
  • 69

2 Answers2

2

Since you are using the mapping plugin, you could specify a create callback. If you add the following to the existing mappingKeys, it would probably work (I don't know your exact mapping, so you might need to change bits here and there):

'MyExistingObservable': {
    create: function(options) {
        return new ko.observable(options.data).extend({ numeric: null });
    }
}

This result in an extended observable upon mapping from yor data.

Here's a jsFiddle with a working example (vm1) and your current non-working example (vm2) for comparison

Major Byte
  • 4,101
  • 3
  • 26
  • 33
  • Thanks! How would this apply to an observable array? Previously I was doing this: $.each(vmRealTimeActivity.Goals(), function (i, e) { e.Count.extend({ numeric: null }); }); >> So I could extend the Count property of the Goals collection that gets automatically generated. I tried something like this: create: function (options) { var newArray = ko.observableArray(options.data); >> Based on your code but no luck. – KingOfHypocrites May 12 '14 at 13:54
  • 1
    [Just to illustrate how you could this with an observable array](http://jsfiddle.net/KrP9D/). There's lots of room for improvement there, but I just wanted to make a quick example. Instead of returning new observables in the 'create' callback, you could return a new viewmodel as well. Just have a look at the [documentation](http://knockoutjs.com/documentation/plugins-mapping.html) for the mapping plugin, the section called **Customizing object construction using “create”** – Major Byte May 12 '14 at 14:50
  • Thanks, I'll take a look. It's ironic, because I had created the view models manually before and I switched to using fromJs, which seems to be more work than it's worth. lol – KingOfHypocrites May 12 '14 at 14:52
  • Sorry to trouble you one last time. I've realized I need to just define the viewmodel and use from JS to refresh it. But, I see no way to get the extend to apply since it's in a child view model and fromJs knows nothing about it. I'm thinking there must be some way to map the child view model when using fromJs? I've made an example so you can see: http://jsfiddle.net/KrP9D/3/ – KingOfHypocrites May 12 '14 at 16:09
  • 1
    Nm, i found the answer here: http://stackoverflow.com/questions/9951521/map-json-data-to-knockout-observablearray-with-specific-view-model-type – KingOfHypocrites May 12 '14 at 16:34
  • @KingOfHypocrites, +1 for actively searching your own solutions, I wish more SO users would be that proactive. – Major Byte May 12 '14 at 16:43
  • How would this be possible without using the mapping plugin? E.g. new mapExample(); ... and ... var mapExample = function() { this.myObservable = ko.observable(); } – Ronald Hulshof Feb 21 '15 at 13:11
  • @RonaldHulshof Did you ever find this answer? I am in need of extending an existing observable without the use of the mapping plugin. I am unable to find anything useful :( – WebDevNewbie Mar 02 '15 at 16:14
  • @WebDevNewbie I ended up using a good old if/else construction. One with the extender, one without. So no, I didn't actually find a solution. – Ronald Hulshof Mar 02 '15 at 19:10
0

The above answer is correct, but for anyone interested, I found the simpler approach is to just create your view models client side and use fromJs to refresh them rather than both create and refresh them. You can then apply the answer here to support adding extend to both your parent and child view models: Map JSON data to Knockout observableArray with specific view model type

With either approach you will have to create additional mappings.

Community
  • 1
  • 1
KingOfHypocrites
  • 9,316
  • 9
  • 47
  • 69