Search code examples
javascriptajaxknockout.jsko.observablearrayhtml-select

Asyncronous knockout observableArray select options loading


I hava a selectOptions ajax-based asincronous loader; it accepts remote address and returns an observable array, correctly populated with descriptions and keyvalues to be accepted by the following binding

 <select data-bind="value: selectedVal, options: opts, optionsText: 'desc', optionsValue:'key', optionsCaption: ''"/></div>

The fact is that, being asincronous, when I trigger a select options change, based on some user actions, I assign it to my model observable array, I do not get the select popuated, but remains empty.

 mymodel.opts = loadOptions("<remoteaddress>");

I know when the second line is called the anwer is not arrived yet, but the returned value is an observableArray, so it should respond correctly whenever is populated, having been assigned to an observable array binded with the ui.

If I hardcode the returned object from the ajax call (when it returns) taking it from console.log in Firefox, or if I pass the observable array opts into the loadOptions, and change it to build up the opts inside it, then it works, but I really need to use loadOptions as is, asincronous. I also tried to append mymodel.opts.valueHasMutated(), but yet ko cannot use the newlly arrived observableArray.

If possible leaving intact the options loader, and if possible without using a custom binding, can I use the incoming observable array for binding when it will be ready?


Solution

  • The problem you've got is that when this line runs:

    mymodel.opts = loadOptions("<remoteaddress>");
    

    it's replacing the entire observable array with a different observableArray, rather than updating the current one. You need to update the existing one - can you change loadOptions to return a normal array, rather than an observable one? You can then do:

    //clear any existing entries
    mymodel.opts.removeAll();
    //push the new entries in
    mymodel.opts.push.apply(mymodel.opts, loadOptions("<remoteaddress>"));