0
votes

I need my select options to have a value because I'm posting the form back to the server and asp.net mvc is going to need to know the value. If I bind and set 'value' to be the instance of an object, which I want to do because other bindings read from the selected objects values, then the options have no html value attribute. The value attribute is what is needed when the form is submitted. If I set the optionsValue and point it to the id of the item then it overrides my value binding and I get errors that the object doesn't have the properties I've bound to.

I can set this up with read/write options on a computed type but I was wondering if there isn't a simpler way.

thanks,

Options have no value;

 <select data-bind="options: $root.meetingEvents,
                    value: $data.meetingEvent,
                    optionsText: 'meetingEventName',
                    optionsCaption: ' '">

Options have value but when selected it's the meetingEventId that is pushed into value and therefor doesn't have the other properties which I have other controls bound to.

<select data-bind=" options: $root.meetingEvents,
                    value: $data.meetingEvent,
                    optionsText: 'meetingEventName',
                    optionsValue: 'meetingEventId'
                    optionsCaption: ' '">
3

3 Answers

0
votes

This is another great reason why they need to add this binding feature to knockout. You shouldn't be restricted to choosing between binding to a value object, or on the valueOption.

You already listed computed observable approach, which I would probably take; using the optionsValue binding open then add a computed observable that keeps the selected object

You could also do something even more strenuous and register a callback on the form submit then dynamically insert the value so that it will be apart of the post ...

0
votes

In the end I added a new computed observable and when the value comes in I find the item from the array and manually set it on my view model.

<select data-bind=" options: $root.meetingEvents,
                    value: $data.meetingEventId,
                    optionsText: 'meetingEventName',
                    optionsValue: 'meetingEventId'
                    optionsCaption: ' '">

//added to the view model

 this.meetingEventId = ko.computed({
                    write: function (value) {
                        var meetingEvent = ko.utils.arrayFirst(vm.meetingEvents(), function (item) {
                            return value === item.meetingEventId();
                        });

                        this.meetingEvent(meetingEvent);
                    },
                    read: function() {
                        return this.meetingEvent() ? this.meetingEvent().meetingEventId : "";
                    },
                    owner: this
                });
0
votes

I would take a slightly different approach. Keep the meetingEventId and meetingEvent properties as observables, but add a subscription to the meetingEventId that updates the meetingEvent when the meetingEventId changes.

HTML

    <select data-bind=" options: $root.meetingEvents,
                value: $data.meetingEventId,
                optionsText: 'meetingEventName',
                optionsValue: 'meetingEventId'
                optionsCaption: ' '">

Javascript

this.meetingEventId = ko.observable('');
this.meetingEvent = ko.observable(null);

this.meetingEventId.subscribe(function(){
    var meetingEventId = this.meetingEventId();
    var meetingEvent = ko.utils.arrayFirst(vm.meetingEvents(), function (item) {
        return meetingEventId === item.meetingEventId();
    });

    this.meetingEvent(meetingEvent);        
});