Search code examples
javascriptknockout.jsknockout-mapping-plugin

KnockoutJS - map multidimensional array


I need map this array to observable array.

actionsDataTime =       {
      "t16082209": [
        {
          "timeId": "16082209",
          "id": 176,
          "class_from": "09:00",
          "class_to": "10:25",
          "action": {
            "name": "AQUA",
            "color": "aqua",
            "icon": ""
          },
          "trainer": {
            "id": 348,
            "name": "Art Edition"
          },
          "capacity": 11,
          "capacity_left": 11,
          "substitutes": 5,
          "substitutes_left": 5,
          "price": 1
        }
      ],
      "t16082308": [
        {
          "timeId": "16082308",
          "id": 169,
          "class_from": "08:00",
          "class_to": "09:00",
          "action": {
            "name": "ZUMBA",
            "color": "zumba",
            "icon": ""
          },
          "trainer": {
            "id": 210,
            "name": "Adam Pt\u00e1\u010dek"
          },
          "capacity": 10,
          "capacity_left": 10,
          "substitutes": 5,
          "substitutes_left": 5,
          "price": 1
        }
      ],
      "t16082408": [
        {
          "timeId": "16082408",
          "id": 173,
          "class_from": "08:00",
          "class_to": "09:05",
          "action": {
            "name": "KICK BOX",
            "color": "box",
            "icon": ""
          },
          "trainer": {
            "id": 360,
            "name": "Alexandra Galov\u00e1"
          },
          "capacity": 10,
          "capacity_left": 10,
          "substitutes": 5,
          "substitutes_left": 5,
          "price": 2
        },
        {
          "timeId": "16082408",
          "id": 175,
          "class_from": "08:00",
          "class_to": "09:05",
          "action": {
            "name": "KICK BOX",
            "color": "box",
            "icon": ""
          },
          "trainer": {
            "id": 360,
            "name": "Alexandra Galov\u00e1"
          },
          "capacity": 10,
          "capacity_left": 10,
          "substitutes": 5,
          "substitutes_left": 5,
          "price": 2
        }
      ]
    }

Section "t16082308" is some timestamp that I need in app so it is dynamic. Number of actions in array can be changed be too.

I am able to map this by mapping module this way

ko.mapping.fromJS(actionsDataTime, self.actionsData);

but when i need to reload it from server like this

self.reloadActions = function() {

                    $.ajax({
                        type: 'GET',
                        url: {link reloadActions! },
                        dataType: "json",
                        success: function(data) {
                            ko.mapping.fromJS(data, {}, self.actionsData);
                        }
                    })
                };

and is there a new timestamp section or soma new action - nothing changes in frontend and it looks that not all things are mapped as observables. When I only change some value like "capacity" it works fine.

How can I map it better (all to observables) so I can see change when actions is added or deleted?


Solution

  • This is how I would do it:

            var actionObj = function (data) {
                this.name = ko.observable();
                this.color = ko.observable();
                this.icon = ko.observable();
                this.update(data);
            }
    
            ko.utils.extend(actionObj.prototype, {
                update: function (data) {
                    this.name = ko.observable(data.name || '');
                    this.color = ko.observable(data.color || '');
                    this.icon = ko.observable(data.icon || '');
                }
            });
    
            self.Action = function (data) {
                return new actionObj(data);
            }
    
            var trainerObj = function (data) {
                this.id = ko.observable();
                this.name = ko.observable();
                this.update(data);
            }
    
            ko.utils.extend(trainerObj.prototype, {
                update: function (data) {
                    this.id = ko.observable(data.id || '');
                    this.name = ko.observable(data.name || '');
                }
            });
    
            self.Trainer = function (data) {
                return new trainerObj(data);
            }
    
            var actionsDataTimeObj = function (data) {
                this.timeId = ko.observable();
                this.id = ko.observable();
                this.class_from = ko.observable();
                this.class_to = ko.observable();
                this.action = ko.observableArray();
                this.trainer = ko.observableArray();
                this.capacity = ko.observable();
                this.capacity_left = ko.observable();
                this.substitutes = ko.observable();
                this.substitutes_left = ko.observable();
                this.price = ko.observable();
                this.update(data);
            }
    
            ko.utils.extend(actionsDataTimeObj.prototype, {
                update: function (data) {
                    this.timeId = ko.observable(data.timeId || '');
                    this.id = ko.observable();
                    this.class_from = ko.observable();
                    this.class_to = ko.observable();
                    var _action = $.map(data.action, function (item) {
                        return new self.Action(item);
                    });
                    this.action(_action);
                    var _trainer = $.map(data.trainer, function (item) {
                        return new self.Trainer(item);
                    });
                    this.trainer(_trainer);
                    this.capacity = ko.observable();
                    this.capacity_left = ko.observable();
                    this.substitutes = ko.observable();
                    this.substitutes_left = ko.observable();
                    this.price = ko.observable();
                }
            });
    
            self.ActionsDataTime = function (data) {
                return new actionsDataTimeObj(data);
            }
    

    Basically you have to declare your "action" and "trainer" as ObservableArrays and then map the data to them in the update function of the ActionsDataTime object. Then everything will be observables.

    Oh, then:

            self.actionsData = ko.observableArray();
            var _actiondatatimes = $.map(data, function (item) {
                return new self.ActionDataTime(item);
            });
            self.actionsData(_actiondatatimes);