Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout group list into smaller lists with objects

I have daily data for multiple employees and depending on the start time and end time that could mean a lot of data.

So with the mapping plugin i mapped them into one big list, but i will need them grouped by employee into smaller lists so i can make a tables per employee (like smaller view models) that has filtering and sorting for that subset of data.

Here is a basic example i created with static data.

$(function () {
    var data = {
        Employees: [{
            Id: 1,
            Name: "Employee1",
            Day: new Date(),
            Price: 12.54
        }, {
            Id: 2,
            Name: "Employee2",
            Day: new Date(),
            Price: 112.54
        }, {
            Id: 1,
            Name: "Employee1",
            Day: new Date(),
            Price: 12.54
        }, {
            Id: 3,
            Name: "Employee3",
            Day: new Date(),
            Price: 12.54
        }]
    };

    // simulate the model to json conversion. from now on i work with the json
    var jsonModel = JSON.stringify(data);

    function employeeModel(data) {
        var employeeMapping = {
            'copy': ["Id", "Name", "Day", "Price"]
        };
        ko.mapping.fromJS(data, employeeMapping, this);
    }

    function employeeViewModel(data) {
        var self = this;
        var employeesMapping = {
            'Employees': {
                create: function (options) {
                    return new employeeModel(options.data);
                }
            }
        };
        ko.mapping.fromJSON(data, employeesMapping, self);
    }

    var productsModel = new employeeViewModel(jsonModel);
    ko.applyBindings(productsModel);
});
table {
    border-collapse: collapse;    
}
table, th, td {
    border: 1px solid black;
}
tr:nth-child(even) {
    background-color: white;
}
tr:nth-child(odd) {
    background-color: #C1C0C0;
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<table>
  <tbody data-bind="foreach: Employees">
    <tr>
      <td><span data-bind="text:Id"></span>
      </td>
      <td><span data-bind="text:Name"></span>
      </td>
      <td><span data-bind="text:Day"></span>
      </td>
      <td><span data-bind="text:Price"></span>
      </td>
    </tr>
  </tbody>
</table>
like image 660
Aleks Avatar asked Feb 06 '15 10:02

Aleks


1 Answers

One possibility would be to use a computed value to group your data.

self.EmployeeGroups = ko.pureComputed(function () {
    var employees = self.Employees(),
        index = {},
        group = [];

    ko.utils.arrayForEach(employees, function(empl) {
        var id = ko.unwrap(empl.Id);
        if ( !index.hasOwnProperty(id) ) {
            index[id] = {
                grouping: {
                    Id: empl.Id,
                    Name: empl.Name
                },
                items: []
            };
            group.push(index[id]);
        }
        index[id].items.push(empl);
    });

    return group;
});

would turn your data from a flat array to this:

[{
    grouping: {
        Id: /* ... */, 
        Name: /* ... */
    }
    items: [/* references to all employee objects in this group */]
}, {
    /* same */
}]

Expand the code snippet below to see it at work.

$(function () {
    var data = {
        Employees: [{
            Id: 1,
            Name: "Employee1",
            Day: new Date(),
            Price: 12.54
        }, {
            Id: 2,
            Name: "Employee2",
            Day: new Date(),
            Price: 112.54
        }, {
            Id: 1,
            Name: "Employee1",
            Day: new Date(),
            Price: 12.54
        }, {
            Id: 3,
            Name: "Employee3",
            Day: new Date(),
            Price: 12.54
        }]
    };

    var jsonModel = JSON.stringify(data);

    function employeeModel(data) {
        var employeeMapping = {
            'copy': ["Id", "Name", "Day", "Price"]
        };
        ko.mapping.fromJS(data, employeeMapping, this);
    }

    function employeeViewModel(data) {
        var self = this;

        self.Employees = ko.observableArray();
        self.EmployeeGroups = ko.pureComputed(function () {
            var employees = self.Employees(),
                index = {},
                group = [];

            ko.utils.arrayForEach(employees, function(empl) {
                var id = ko.unwrap(empl.Id);
                if ( !index.hasOwnProperty(id) ) {
                    index[id] = {
                        grouping: {
                            Id: empl.Id,
                            Name: empl.Name
                        },
                        items: []
                    };
                    group.push(index[id]);
                }
                index[id].items.push(empl);
            });

            return group;
        });

        // init
        var employeesMapping = {
            'Employees': {
                create: function (options) {
                    return new employeeModel(options.data);
                }
            }
        };
        ko.mapping.fromJSON(data, employeesMapping, self);
    }

    var productsModel = new employeeViewModel(jsonModel);
    ko.applyBindings(productsModel);
});
table {
    border-collapse: collapse;    
}
table, th, td {
    border: 1px solid black;
}
tr:nth-child(even) {
    background-color: #efefef;
}
tr:nth-child(odd) {
    background-color: #CCCCCC;
}
tr.subhead {
    background-color: #D6E3FF;
    font-weight: bold;
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<table>
  <!-- ko foreach: EmployeeGroups -->
  <tbody>
    <!-- ko with: grouping -->
    <tr class="subhead">
      <td colspan="2">
        <span data-bind="text: Id"></span>
        <span data-bind="text: Name"></span>
      </td>
    </tr>
    <!-- /ko -->
    <!-- ko foreach: items -->
    <tr>
      <td><span data-bind="text: Day"></span></td>
      <td><span data-bind="text: Price"></span></td>
    </tr>
    <!-- /ko -->
  </tbody>
  <!-- /ko -->
</table>

<pre data-bind="text: ko.toJSON($root, null, 2)" style="font-size: smallest;"></pre>
like image 64
Tomalak Avatar answered Nov 01 '22 18:11

Tomalak