Search code examples
javascriptc#htmlknockout.jsknockout-2.0

Grouping a list by a property


Hi i am trying to do a table grouping of a list of class. I am following the code at this page The issue I have is with this line

<ul data-bind="foreach: $root.people.index.type()[$data]">

In my case it doesnt recognize type well in my case courseCode.

Now here how I did mine

<table class="table table-striped">
    <thead>
        <tr>
            <th>ID</th>
            <th>Course Code</th>
            <th>Course Title</th>
            <th>Course Campus</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: gpCourseCode">
        <tr>
            <td data-bind="text: $data"></td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr data-bind="foreach: $root.courses.index.courseCode()[$data]">
            <td><span data-bind="text: ID"></span></td>
            <td><span data-bind="text: courseCode"></span></td>
            <td><span data-bind="text: courseTitle"></span></td>
            <td><span data-bind="text: coursecampus"></span></td>
        </tr>
    </tbody>
</table>

This is my javascript

ko.observableArray.fn.distinct = function (prop) {
    var target = this;
    target.index = {};
    target.index[prop] = ko.observable({});

    ko.computed(function () {
        //rebuild index
        var propIndex = {};

        ko.utils.arrayForEach(target(), function (item) {
            var key = ko.utils.unwrapObservable(item[prop]);
            if (key) {
                propIndex[key] = propIndex[key] || [];
                propIndex[key].push(item);
            }
        });

        target.index[prop](propIndex);
    });

    return target;
};    

function course(_id, _courseCode, _courseTitle, _courseCampus) {
    var self = this;
    this.id = ko.observable(_id);
    this.courseCode = ko.observable(_courseCode);
    this.courseTitle = ko.observable(_courseTitle);
    this.coursecampus = ko.observable(_courseCampus);
}

function ViewModel() {
    var self = this;
    this.courses = ko.observableArray();
    this.gpCourseCode = ko.observableArray().distinct('courseCode');

    self.courses.push(new course("1", "MATH1030", "Calculus", "City2"));
    if (self.gpCourseCode().indexOf("MATH1030") == -1) {
        self.gpCourseCode.push("MATH1030");
    }
    self.courses.push(new course("2", "MATH1030", "Calculus", "City1"));
    if (self.gpCourseCode().indexOf("MATH1030") == -1) {
        self.gpCourseCode.push("MATH1030");
    }
    self.courses.push(new course("3", "MATH1030", "Calculus", "City3"));
    if (self.gpCourseCode().indexOf("MATH1030") == -1) {
        self.gpCourseCode.push("MATH1030");
    }
    self.courses.push(new course("4", "MATH1006", "Linear algebra", "City2"));
    if (self.gpCourseCode().indexOf("MATH1006") == -1) {
        self.gpCourseCode.push("MATH1006");
    }
    self.courses.push(new course("5", "MATH1046", "Discrete Math", "City2"));
    if (self.gpCourseCode().indexOf("MATH1046") == -1) {
        self.gpCourseCode.push("MATH1046");
    }
    self.courses.push(new course("6", "MATH1006", "Linear algebra", "City1"));
    if (self.gpCourseCode().indexOf("MATH1006") == -1) {
        self.gpCourseCode.push("MATH1006");
    }
    self.courses.push(new course("7", "MATH1046", "Discrete Math", "City1"));
    if (self.gpCourseCode().indexOf("MATH1046") == -1) {
        self.gpCourseCode.push("MATH1046");
    }
}

Solution

  • The .distinct('courseCode') is on the wrong observable array. it should be on the this.courses = ko.observableArray() because that is the array that you are grouping.

    ko.observableArray.fn.distinct = function (prop) {
        var target = this;
        target.index = {};
        target.index[prop] = ko.observable({});
    
        ko.computed(function () {
            //rebuild index
            var propIndex = {};
    
            ko.utils.arrayForEach(target(), function (item) {
                var key = ko.utils.unwrapObservable(item[prop]);
                if (key) {
                    propIndex[key] = propIndex[key] || [];
                    propIndex[key].push(item);
                }
            });
    
            target.index[prop](propIndex);
        });
    
        return target;
    };    
    
    function course(_id, _courseCode, _courseTitle, _courseCampus) {
        var self = this;
        this.id = ko.observable(_id);
        this.courseCode = ko.observable(_courseCode);
        this.courseTitle = ko.observable(_courseTitle);
        this.coursecampus = ko.observable(_courseCampus);
    }
    
    function ViewModel() {
        var self = this;
        this.courses = ko.observableArray().distinct('courseCode');
        this.gpCourseCode = ko.observableArray();
    
        self.courses.push(new course("1", "MATH1030", "Calculus", "City2"));
        if (self.gpCourseCode().indexOf("MATH1030") == -1) {
            self.gpCourseCode.push("MATH1030");
        }
        self.courses.push(new course("2", "MATH1030", "Calculus", "City1"));
        if (self.gpCourseCode().indexOf("MATH1030") == -1) {
            self.gpCourseCode.push("MATH1030");
        }
        self.courses.push(new course("3", "MATH1030", "Calculus", "City3"));
        if (self.gpCourseCode().indexOf("MATH1030") == -1) {
            self.gpCourseCode.push("MATH1030");
        }
        self.courses.push(new course("4", "MATH1006", "Linear algebra", "City2"));
        if (self.gpCourseCode().indexOf("MATH1006") == -1) {
            self.gpCourseCode.push("MATH1006");
        }
        self.courses.push(new course("5", "MATH1046", "Discrete Math", "City2"));
        if (self.gpCourseCode().indexOf("MATH1046") == -1) {
            self.gpCourseCode.push("MATH1046");
        }
        self.courses.push(new course("6", "MATH1006", "Linear algebra", "City1"));
        if (self.gpCourseCode().indexOf("MATH1006") == -1) {
            self.gpCourseCode.push("MATH1006");
        }
        self.courses.push(new course("7", "MATH1046", "Discrete Math", "City1"));
        if (self.gpCourseCode().indexOf("MATH1046") == -1) {
            self.gpCourseCode.push("MATH1046");
        }
    }
    
    ko.applyBindings(new ViewModel());
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css" rel="stylesheet"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    <pre data-bind="text: ko.toJSON($root)"></pre>
    
    <table class="table table-striped">
        <thead>
            <tr>
                <th>ID</th>
                <th>Course Code</th>
                <th>Course Title</th>
                <th>Course Campus</th>
            </tr>
        </thead>
        <tbody data-bind="foreach: gpCourseCode">
            <tr>
                <td data-bind="text: $data"></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <!-- ko foreach: $root.courses.index.courseCode()[$data] -->
            <tr>
                <td><span data-bind="text: id"></span></td>
                <td><span data-bind="text: courseCode"></span></td>
                <td><span data-bind="text: courseTitle"></span></td>
                <td><span data-bind="text: coursecampus"></span></td>
            </tr>
            <!-- /ko -->
        </tbody>
    </table>