Knockout/Kendo ComboBoxBinding :: Write on change

300 views
Skip to first unread message

BOX

unread,
Nov 15, 2012, 12:23:51 PM11/15/12
to knock...@googlegroups.com
Let's say I have my data Items and all is well...the selector is created in a forEach: loop within a table cell ::
 <select data-bind="kendoComboBox: { data: WorkTypes, value: WorkType, dataTextField: 'Description' }" />

All looks good until I make a change.
My WorkType is ko.computed. When I make a change I also need to account for the 'write' method, which is where my question site.
The type that comes back over is [Object object] and I cannot access the values such that I can update the view model.
How can I control the 'val' in the write method below so I can get the values I need from it?

self.WorkType = ko.computed({
        read: function () {
            if (self.WorkTypeId() == nullreturn {};
            var wt = ko.utils.arrayFirst(self.WorkTypes(), function (item) {
                return item.Key == self.WorkTypeId();
            });
            return (!wt) ? {} : wt;
        },
        write: function (val) {
            self.WorkTypeId(val);
        }
    });

rpn

unread,
Nov 16, 2012, 10:09:16 AM11/16/12
to knock...@googlegroups.com
Maybe you would want to go with something more like: http://jsfiddle.net/rniemeyer/WEuut/  This uses "dataValueField" to make sure that the Id is written to an observable and then uses a computed to represent the actual object.

beauXjames

unread,
Nov 16, 2012, 10:28:09 AM11/16/12
to knock...@googlegroups.com
Actually ended up being just about exactly what I did to make this one work. My only question would be to what the advantage of having the additional ', this' at the end of your function method. Is it not enough to already be in the appropriate scope via the 'self' or 'this' space declared in the name of the property? aka self.WorkType 
self.WorkType = ko.computed(function () {
    var wt = ko.utils.arrayFirst(self.WorkTypes(), function (item) {
        return item.Key == self.WorkTypeId();
    });
    return (!wt) ? { Description: '' } : wt;
});

---------------------
beauXjames tschirhart
experiMental living room
m. 512.496.8528

shau...@gmail.com

unread,
Nov 16, 2012, 2:10:43 PM11/16/12
to knock...@googlegroups.com
From my understanding, it's kind of an either or type of thing. 

If you use self you don't need to append the ,this) as that's what provides the context for this.

BOX

unread,
Nov 16, 2012, 2:34:47 PM11/16/12
to knock...@googlegroups.com
I would think that as well, however in the example fiddle by rpn, he's got 'this' in both places...so the question lingers

rpn

unread,
Nov 16, 2012, 2:52:55 PM11/16/12
to knock...@googlegroups.com
The second argument to a computed observable (and manual subscription) allows you to bind the handler to a specific context, so you can have a reliable value of "this" when executing the function.

So, in my example it looks like:

var ViewModel function({
    this.choices ko.observableArray([
        id"1"name"apple"},
        id"2"name"orange"},
        id"3"name"banana"}
    ]);

    this.selectedId ko.observable();
    
    this.selectedObject ko.computed(function({
        var id this.selectedId();
        return ko.utils.arrayFirst(this.choices()function(choice{
            return id === choice.id;
        });
    }this);
};

One common alternative is to cache the appropriate value of "this" in a variable and then reference it directly in the handler (variable is available based on how closures work in JS).  In this case, it is not necessary to pass the second argument, as "this" is not a concern.  So, it would look like:

var ViewModel function({
    var self this;
    this.choices ko.observableArray([
        id"1"name"apple"},
        id"2"name"orange"},
        id"3"name"banana"}
    ]);

    this.selectedId ko.observable();
    
    this.selectedObject ko.computed(function({
        var id this.selectedId();
        return ko.utils.arrayFirst(self.choices()function(choice{
            return id === choice.id;
        });
    });
};

You could certainly certainly say "self.items', "self.selectedId", etc. in the constructor, but the only place where "this" is a concern is when executing the handler.  In this case, using "self.choices()" in the handler makes it so we don't need to use "this" at all.

Hope that makes sense.

BOX

unread,
Nov 16, 2012, 3:11:23 PM11/16/12
to knock...@googlegroups.com
Maybe this follow-up is more of a base js questions, however with such a great lead-in, I couldn't think of a better example...

In most cases, when I am needing to create an object with properties and the sort, I always start with var self = this;
After that, I never use 'this'...only 'self'.

are there some drawbacks to this?
Is 'self' not really 'this'?

thanks!

rpn

unread,
Nov 19, 2012, 2:33:00 PM11/19/12
to knock...@googlegroups.com
Using "self" in the way that you describe definitely removes any concerns that a function will run with the wrong context (this).

One case where "self" does not work as well is when you want to place functions on the prototype or attach a function reference that you are not creating anonymously.  In that case, you will still need to bind your function or use the second argument to computed or subscriptions. 

Here is a simplistic example:

​var MyType function(data{
    this.first ko.observable(data.first);
    this.last ko.observable(data.last);
    this.fullName ko.computed(this.getFullNamethis);    
};

​MyType.prototype.getFullName function({
    return this.first(" " this.last();  
};
Reply all
Reply to author
Forward
0 new messages