0

Within my model I have an object array with observable elements. I have a subscribe on one of these elements (a dropdown list) in order to fill in the next dropdown (cascading dropdowns). I now need to get the description of the selected value in these dropdowns. How would I pull that value from the dropdown list? I am trying to avoid running a query against the server if possible.

In the past I have done self.deptName($('#AssignedDepartment option:selected').text()); but now this dropdown isn't unique. I could have many to choose from. I am using uniqueName: true on each of the fields. How, within the subscribe, do I determine which dropdown changed?

Here is what my subscribe looks like:

    // Build the hours types when the request type is selected
    self.RequestType.subscribe(function (newValue) {
        FindRequestType(newValue, function (record) {
            // Do stuff
        });
    });

Here is the HTML for the dropdown:

<select class="required span12" data-bind="leaveTypeDropDown: RequestType, uniqueName: true"></select>

Here is the bindingHandler:

ko.bindingHandlers.leaveTypeDropDown = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // If we don't have the leave request dropdown data, pull it.
        if (jsonRequestType === "") {
            $.ajax({
                'async': false,
                'url': '/api/payroll/LeaveRequestTypes/',
                'dataType': 'text json',
                'type': 'GET',
                'success': function (json) {
                    jsonRequestType = json;
                    jsonRequestTypeRecieved = true;
                }
            });
        }

        // Fill the drop down list.
        LoadRequestType(element);

        // register event handler where bound observable will be changed
        ko.utils.registerEventHandler(element, 'change', function () {
            var observable = valueAccessor();
            observable(element.value);
        });

        // Select the value from the previous record if there is one.
        if (selectedRequestType !== null) {
            element.value = selectedRequestType;
            ko.utils.triggerEvent(element, 'change');
            selectedRequestType = null;
        }
    }
};

Update 1: Since there is confusion. If I select the value "VAC" with the text of "Vacation" in my dropdown list. How do I get the text "Vacation" into my model?

Update 2: Here is a jsFiddle with my (mostly) working code as listed above. http://jsfiddle.net/MikeWills/cykuqxto/6/ For some reason, on load my drop downs don't work, but add another day and you'll see my working dropdowns.

Mike Wills
  • 20,959
  • 28
  • 93
  • 149
  • this depends on how you bind your dropdown with knockout. Your self.RequestType is going to receive a context and a value passed to the subscription. If you update your sample code to show your HTML, it would be easier to help. Pre-emptively, I'd guess you should check this out if you haven't: http://knockoutjs.com/documentation/options-binding.html – Milimetric Sep 16 '14 at 17:13
  • @Milimetric added that HMTL – Mike Wills Sep 16 '14 at 18:18
  • You write the question "How, within the subscribe, do I determine which dropdown changed?" and I would say that with a MVVM mindset you shouldn't. The viewmodels should have the data, the view is a UI for the viewmodels. The view knows of the viewmodel, the viewmodel shouldn't know of the view. You also ask "How would I pull that value [description] from the dropdown list?" and the answer would be that you pull it from the viewmodel, not the dropdown list. But I'm guessing that I just don't understand what you are actually asking about. Could you please clarify your question? – Robert Westerlund Sep 16 '14 at 20:06
  • So what is the proper way to code my dropdown list so that the model knows the text of each value in the dropdown? – Mike Wills Sep 16 '14 at 20:09

1 Answers1

1

We have to clean up your approach a little bit. First, let's make all the observables we need on your model and populate the first drop down choices with your ajax call:

var viewModel = {
    firstDropDownOptions: ko.observableArray(),
    firstDropDownChoice: ko.observable()
};

$.ajax(...).done(function (data) {
    // process data and assign
    // for the binding below to work, processedData has to have items like this:
    // {textProperty: 'some text', otherProperty: ...}
    // as you said in a comment, you have option groups so I'm going to assume
    // processedData looks like this overall:
    // [{group: 'one', options: [{text: 'Vacation', value: 'VAC'}, ...]}, ...]
    viewModel.firstDropDownOptions(processedData);
});

Then let's bind that observable to your drop down using the options binding

<select data-bind="foreach: firstDropDownOptions, value: firstDropDownChoice">
    <optgroup data-bind="attr: {label: label}, foreach: options">
        <option data-bind="text: text, option: $data"></option>
    </optgroup>
</select>

This is using the custom binding from KnockoutJS - Binding value of select with optgroup and javascript objects:

ko.bindingHandlers.option = {
    update: function(element, valueAccessor) {
       var value = ko.utils.unwrapObservable(valueAccessor());
       ko.selectExtensions.writeValue(element, value); // note this is magic
    }        
};

Finally, let's subscribe to the observable that monitors changes to this first drop down:

viewModel.firstDropDownChoice.subscribe(function (newChoice) {
    // in this function, newChoice is the option selected in the first drop down,
    // but not just the value, the whole object, so you can do:
    console.log(newChoice, newChoice.text);
});
Community
  • 1
  • 1
Milimetric
  • 13,411
  • 4
  • 44
  • 56
  • The problem with this for my dropdown is that I am using Option Groups in my dropdown for ease of use. So this wouldn't work in this case. But I'll remember this for future times I work with dropdowns. I added a jsFiddle, that at least shows what I am doing though it's a bit buggy. – Mike Wills Sep 17 '14 at 02:46
  • The same principle applies, though if you have option groups you'd have to bind your choices manually. I'll update the code above. – Milimetric Sep 17 '14 at 02:56
  • I've updated, the key was using a custom option binding to make sure your selected item is a full object instead of just one of the properties of the option you're binding. – Milimetric Sep 17 '14 at 03:06
  • Thanks @Milimetric I'll look into this further tomorrow. – Mike Wills Sep 17 '14 at 03:10