ksdev
ksdev

Reputation: 1

Knockout.js - handling data from tables joined by a foreign key

As a beginner in Knockout.js I have a problem with handling data from tables joined by a foreign key.

Let's say we have such a simple code:

function AppViewModel() {
    var self = this;

    self.users = ko.observableArray([
        {id: 0, name: "Willi", surname: "Jederman", meal: {id: 1, name: "Orange", price: 25.00}},
        {id: 1, name: "Hans", surname: "Kloss", meal: {id: 2, name: "Carrot", price: 300.00}}
    ]);

    self.meals = ko.observableArray([
        {id: 0, name: "Apple", price: 10.00},
        {id: 1, name: "Orange", price: 25.00},
        {id: 2, name: "Carrot", price: 300.00}
    ]);

    self.addUser = function() {
        self.users.push({id: null, name: "", surname: "", meal: {id: 0, name: "Apple", price: 10.00}});
    };    

    self.removeUser = function(user) {
        self.users.remove(user);
    };
}

ko.applyBindings(new AppViewModel());

The data:

{id: 0, name: "Willi", surname: "Jederman", meal: {id: 1, name: "Orange", price: 25.00}}

is taken from two tables - server returns rows from 'users' and 'meals' tables as one json - these are joined by a foreign key "meal_id" in the 'users' table.

I can also fetch this data as:

{id: 0, name: "Willi", surname: "Jederman", meal_id: 1}

Now I wish to show a simple table with this data:

name | surname | meal name | meal price

where 'meal name' is a select with options taken from 'self.meals' and with current user 'meal.id' selected.

I have a problem with 'meal price' - it should change automatically with 'meal name' select change, but I don't know how to do it.

My 'meal name' select looks like this:

(inside a data-bind="foreach: users":)

<select data-bind="options: $root.meals,
                   optionsValue: 'id',
                   optionsText: 'name',
                   value: meal.id"></select>

I don't know what binding should I give to 'meal price'? I know, that it should start from 'data-bind="text:'...

Thanks for any help.

Upvotes: 0

Views: 542

Answers (1)

Max Brodin
Max Brodin

Reputation: 3938

You need class for user like this

function User(user, root) {

    this.id = ko.observable(user.id);
    this.name = ko.observable(user.name);
    this.surname = ko.observable(user.surname);
    this.mealId = ko.observable(user.mealId);

    this.root = root;

    this.currentMeal = ko.computed(function () {
        var mealId = this.mealId();
        return ko.utils.arrayFirst(this.root.meals, function(item) {
            return item.id === mealId;
        });
    }, this);
}

Note currentMeal computed, that finds the meal by it's id from the root model data.

Сonnect your models with root parameter

function AppViewModel() {

    this.meals = [
        { id: 0, name: "Apple", price: 10.00 },
        { id: 1, name: "Orange", price: 25.00 },
        { id: 2, name: "Carrot", price: 300.00 }
    ];

    this.users = ko.observableArray([
        new User({id: 0, name: "Willi", surname: "Jederman", mealId: 1}, this),
        new User({id: 1, name: "Hans", surname: "Kloss", mealId: 2}, this)
    ]);

    this.addUser = function() {
        this.users.push(new User({id: null, name: "", surname: "", mealId: 0}), this);
    };    

    this.removeUser = function(user) {
        this.users.remove(user);
    };
}

See fiddle

Upvotes: 1

Related Questions