Umair
Umair

Reputation: 3243

Knockout observable array. Shared between multiple view models

Got a bit of a conundrum with a knockout observable array being shared across multiple view models.

Basically, I have a layout as follows

Transport
    ... textbox fields, etc

    Selected Passengers:
        <!-- ko foreach: allPassengers -->   
        <input type="checkbox" />
        <!-- /ko -->

    <button>Add Transport</button>

Holiday
    ... textbox fields, etc

    Selected Passengers:

        <!-- ko foreach: allPassengers -->   
        <input type="checkbox" />
        <!-- /ko -->

    <button>Add Holiday</button>

Now the selected passengers for each section is being generated from ONE observable array, idea being if a passenger is deleted/altered everything should fall into place automagically.

So something like this

function page() {
    // in actuality this passengers array is a computed observable obtained from the passengers section which is not shown here.
    this.allPassengers = ko.observableArray([
    {
        Id: 1,
        name = ko.observable('name'),
        checked = ko.observable(false)
    },
    {
     .
     .
    ]);
}

function transport() {
    // pageVM is a page object
    this.allPassengers = pageVM.allPassengers;

    this.transportItems = ko.observableArray();

    this.addTransport = function() {
        this.transportItems.push({
            .
            .
            selectedPassengers: [...]
            .
            .
        });
    };
}

function holiday() {
    // pageVM is a page object
    this.allPassengers = pageVM.allPassengers;

    this.holidayItems = ko.observableArray();

    this.addHoliday = function() {
        this.holidayItems.push({
            .
            .
            selectedPassengers: [...]
            .
            .
        });
    };
}

However, when add transport/holiday is clicked, I need a way to determine which checkboxs where checked so I can add the selected passengers.

I have tried to add a checked = ko.observable(false) property to the passenger item in parent.allPassengers, but the problem with this approach is if a checkbox is checked in the transport section it will also check it in the holiday section since it is using the same observable array.

Any ideas??

Edit:

example fiddle

Upvotes: 4

Views: 2240

Answers (2)

sellmeadog
sellmeadog

Reputation: 7517

You can use a ko.computed to return the selected passengers (and here's a fiddle):

var ViewModel = function () {
    this.allPassengers = ko.observableArray([
        { name: 'John', selected: ko.observable(false) },
        { name: 'Jane', selected: ko.observable(false) },
        { name: 'Mark', selected: ko.observable(false) }
    ]);

    this.selectedPassengers = ko.computed(function () {
        return ko.utils.arrayFilter(this.allPassengers(), function (item) {
            return item.selected();
        });
    }, this);
};

Upvotes: 0

david.s
david.s

Reputation: 11403

The checked binding works with observable arrays too. So you can simply bind to $parent.selectedPassengers and specify the value attribute to be the passenger id, like this:

<input type="checkbox" data-bind="attr: { value: id },
                                  checked: $parent.selectedPassengers" />

In each view model you need to have a selectedPassengers observable array used for binding to the checkbox. And the add function should look like this:

function transport(pageVM) {
    ....
    this.selectedPassengers = ko.observableArray([]);    
    ....

    this.addTransport = function() {
        this.selectedItems.push({ 
            ....
            selectedPassengers: this.selectedPassengers()
        });
    };    
};

Working Fiddle

Upvotes: 4

Related Questions