kmalakoff/knockback

Single selectbox

Closed this issue · 3 comments

I have a relation between a Page and PageType model, which I have defined like so:

var Page = Backbone.RelationalModel.extend({});

var PageType = Backbone.RelationalModel.extend({
            relations: [
                {
                    type: 'HasMany',
                    key: 'pages',
                    relatedModel: Page,
                    reverseRelation: {
                        key: 'page_type_id'
                    }
                }
            ]
        });

var PageTypeCollection = Backbone.Collection.extend({
        model: PageType
    });

The view model for the Page loads a list of the available PageTypes, and also has a reference to it's own page_type_id.

var PageEditViewModel = function(model) {
            var _this = this;

            this._auto = kb.viewModel(model, {
                keys: {
                    page_type_id: { key: 'page_type_id' }
                }
            });

            this.pageTypes = kb.collectionObservable(new PageTypeCollection(), {
                defer: true
            });
}

And the view like so:

  <select data-bind="options: pageTypes, optionsValue: 'id', optionsText: 'name', value: page_type_id"></select>

I figure I'm missing a step here, but cannot find anything in the documentation - the 'shareOptions' didn't seem to be entirely relevant to this problem. Any pointers would be appreciated! :)

@rikdc - shareOptions are used for sharing view models across collection observable and view model boundaries; for example, in the case of a select tag, but should be handled automatically if the models are in the same hierarchy.

I've taken a look at this, but am not totally sure why you are using so many features. For example, what's the _auto for, why are you defering the collectionObservable, and why are you using such a long form of kb.viewModel and a view model in the first place when a single kb.observable would do?

Maybe you just need something simple like:

var PageEditViewModel = function(model) {
  this.page_type_id = kb.observable(model, 'page_type_id')
  this.pageTypes = kb.collectionObservable(new PageTypeCollection());
}

I think the best thing to do would be for you to create a jsFiddle with an actual use case that I can look at.

Thanks for getting back to me, the honest answer for using all the features - I'm hacking away to learn how this works, so there's a lot of bloat in my code just now.

Here is a fiddle created to demonstrate what I am trying to do.

http://jsfiddle.net/T9MVM/3

It appears that it does work and update after the model has been loaded, but the initial value (page_type_id = 2) seems to be lost as the page is loaded.

OK. I've looked at your jsFiddle. If I change:

<select data-bind="options: pageTypes, optionsValue: 'id', optionsText: 'name', value: page_type_id"></select>

to

<select data-bind="options: pageTypes, optionsValue: 'id', optionsText: 'name'"></select>

...the initial value of 2 for page_type_id is used. The select binding is setting the 'page_type_id' observable value when it is initialized and also sets the page_type_id in the model which is why page_type_id is changed from what is initially in the Backbone.Model (2 -> 1).

You'll need to play around with the select binding and find a better way to handle delayed initialization to fit your needs (for example, in the fetch callback, you could query the Backbone model's initial state and set it manually if it exists in the fetched response).