Skip to Main Content

DevOps, CI/CD and Automation

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Multi select does not work when binding options from REST call

2930948Apr 5 2016 — edited Apr 12 2016

Hello,

I am having trouble with multi select. The problem is when I get the data for the options from the REST call then upon selecting the option it shows it's value in the select and not the label.

Here is some example code for the problem (for the simplicity of the example let's assume that the view model is properly bind to the select element, $ variable is jQuery object, url is variable containing the endpoint url of the server, the REST call is successful and the returned data is in following format:

     [{value: '1', label:'Label for item 1'}, {value: '2', label: 'Label for item 2'}, {value: '3', label: 'Label for item 3'}]

):

HTML snippet:

<label for="select">Select with options array</label>

<select id="select" data-bind="ojComponent: {component: 'ojSelect', options: browsers, multiple: true,

                                             rootAttributes: {style:'max-width:20em'}}">

</select>

and Javascript

function selectModel () {

    var self = this;

    this.browsers = ko.observableArray([]);

     $.getJSON(url, function(data) {

          self.browsers(data);

     });

  }

The problem is that in this example the options in the select are correct - Label for item 1, Label for item 2, .... But when one of them is selected then inside the select box it's value is shown eg. '1' instead of the label. This is problem only with multi select and when setting options in the callback from the REST call, single select works fine.

Any ideas how to solve this?

Thank you

Vasek Stebra

This post has been answered by Jim.Marion-Oracle on Apr 6 2016
Jump to Answer

Comments

John JB Brock-Oracle

Hi Vasek,

Changing your data to look like this:

[

{"value": "1", "label":"Label for item 1"},

{"value": "2", "label": "Label for item 2"},

{"value": "3", "label": "Label for item 3"}

]

Corrects the behavior in my test code.  What you have shown is not valid JSON.

Hope that helps

2930948

Hi John,

thank you for your reply. Yes what I shown is not valid JSON, what I shown is the JSON already converted to Javascript array - I apologize for misunderstanding - didn't realize that. However in my code I use valid JSON (generated by json_encode function in PHP) and it still does not work as expected.

Let's take the JSON out of the game and try this simpler example, which simulates the delay when doing the REST call and also does not work as expected. After the 2 second, the options for the select are set correctly, but again when one of them is selected it's value instead of the label appears in the select box.

<label for="select">Select with options array</label> 

<select id="select" data-bind="ojComponent: {component: 'ojSelect', options: browsers, multiple: true, 

                                             rootAttributes: {style:'max-width:20em'}}"

</select>

function selectModel () { 

     var self = this

     this.browsers = ko.observableArray([]); 

     window.setTimeout(function(){

          var data = [{value: '1', label:'Label for item 1'}, {value: '2', label: 'Label for item 2'}, {value: '3', label: 'Label for item 3'}];

          self.browsers(data);

     }, 2000);

Thank you

Vasek

Jim.Marion-Oracle
Answer

I put together a jsfiddle with your example and then started fiddling with it. It is very interesting that just commenting out the window.setTimeout makes it behave properly. This makes me question the way the bindings and observables behave.

I noticed that you are completely replacing the array referenced by the observable. In most cases, that seems to be acceptable. I have trouble with that sometimes, though, so I use the ko helper methods to update the originally bound array rather than replace the array. Here is a jsFiddle that uses ko.utils.arrayPushAll and valueHasMutated to push the Ajax response into the observable's existing array. This version works the way you expect:

https://jsfiddle.net/jmarion/8079eeoc/

Marked as Answer by 2930948 · Sep 27 2020
2930948

Hello Jim,

thank you, your solution works great for me.

John JB Brock-Oracle

The other option for trying to control when the DOM is loaded versus when the data is ready, is to use a Knockout virtual "if" binding.

Using your code, it would look like this in the HTML

<!-- ko if: dataReady -->

<label for="select">Select with options array</label>  

<select id="select" data-bind="ojComponent: {component: 'ojSelect', options: browsers, multiple: true,  

                                            rootAttributes: {style:'max-width:20em'}}">  

</select>

<!-- /ko -->

Then in the JavaScript you add the ko observable for dataReady and initialize it to false.  Once the data has been returned, you set the value to true.  I modified your getJSON call to use the Promise ( .then ) provided by jQuery as well in the code below.

function selectModel () { 

    var self = this;

     self.browsers = ko.observableArray([]); 

     self.dataReady = ko.observable(false);

     $.getJSON(url).then(function(data) { 

          self.browsers(data);

          self.dataReady(true); 

     }); 

  } 

Hope this helps others down the road.  It's a really common use case.

1 - 5

Post Details

Added on Apr 5 2016
5 comments
3,417 views