In Knockout.js, what is the best way to nest object inside of an an array?
I am trying to have an observable that is sorted by a group of courses title and inside there would be different course offered to a student with the same group property ( course code).
This is my snippet
function course(_id, _code, _title, _campus) {
var self = this;
this.id = ko.observable(_id);
this.courseCode = ko.observable(_code);
this.courseTitle = ko.observable(_title);
this.coursecampus = ko.observable(_campus);
}
function gpCourseProperties(_code, _isHidden) {
var self = this;
this.gpCode = ko.observable(_code);
this.hide = ko.observable(_isHidden);
this.courses = ko.observableArray();
this.addCourse = function (_id, _courseCode, _courseTitle, _courseCampus) {
self.courses.push(new course(_id, _courseCode, _courseTitle, _courseCampus));
}
this.switchMutated = function (code) {
self.hide(!self.hide());
};
this.switchText = ko.computed(function () {
if (self.hide() == true) {
return '+'
}
return '-';
}, this);
}
function ViewModel() {
var self = this;
this.gpCourseProp = ko.observableArray();
self.gpCourseProp.push(new gpCourseProperties("MATH1030", true));
self.gpCourseProp.push(new gpCourseProperties("MATH1006", true));
self.gpCourseProp.push(new gpCourseProperties("MATH1046", true));
for (i = 0; i < self.gpCourseProp().length; i++) {
if (self.gpCourseProp()[i].gpCode == "MATH1030") {
self.gpCourseProp()[i].addCourse(new course("1", "MATH1030", "Calculus", "City1"));
self.gpCourseProp()[i].addCourse(new course("2", "MATH1030", "Calculus", "City2"));
self.gpCourseProp()[i].addCourse(new course("3", "MATH1030", "Calculus", "City3"));
}
if (self.gpCourseProp()[i].gpCode == "MATH1006") {
self.gpCourseProp()[i].addCourse(new course("4", "MATH1006", "Linear algebra", "City1"));
self.gpCourseProp()[i].addCourse(new course("6", "MATH1006", "Linear algebra", "City2"));
}
if (self.gpCourseProp()[i].gpCode == "MATH1046") {
self.gpCourseProp()[i].addCourse(new course("5", "MATH1046", "Discrete Math", "City1"));
self.gpCourseProp()[i].addCourse(new course("7", "MATH1046", "Discrete Math", "City2"));
}
}
}
var vm = new ViewModel();
ko.applyBindings(vm);
tr.mutated {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Course Code</th>
<th>Course Title</th>
<th>Course Campus</th>
</tr>
</thead>
<tbody data-bind="foreach: gpCourseProp">
<tr class="table-dark">
<td></td>
<td><span data-bind="text: $data.gpCode"></span></td>
<td><span></span></td>
<td></td>
</tr>
<!-- ko foreach: $data.courses -->
<tr data-bind="css: { mutated: $parent.mutated.hide() == true }">
<td><span data-bind="text: $data.id"></span></td>
<td><span data-bind="text: $data.courseCode"></span></td>
<td><span data-bind="text: $data.courseTitle"></span></td>
<td><span data-bind="text: $data.coursecampus"></span></td>
</tr>
<!-- /ko -->
</tbody>
</table>
The issue i have is trying to add courses to the gpCourseProperties.
Main issues are:
push
the arguments for gpCourseProperties
to the observable array. You need to construct the viewmodel using new
.course
content for your courseProperties
, you check gpCode === "Some string"
. Since gpCode
is observable
, you need to extract its value using ()
for this to ever be true.Here's an updated version with the minimum changes required to make it work. (note, I removed the CSS that hid some of the rows for debug purposes).
The fixes are marked in the comments.
function course(_id, _code, _title, _campus) {
var self = this;
this.id = ko.observable(_id);
this.courseCode = ko.observable(_code);
this.courseTitle = ko.observable(_title);
this.coursecampus = ko.observable(_campus);
}
function gpCourseProperties(_code, _isHidden) {
var self = this;
this.gpCode = ko.observable(_code);
this.hide = ko.observable(_isHidden);
this.courses = ko.observableArray();
this.addCourse = function (_id, _courseCode, _courseTitle, _courseCampus) {
self.courses.push(new course(_id, _courseCode, _courseTitle, _courseCampus));
}
this.switchMutated = function (code) {
self.hide(!self.hide());
};
this.switchText = ko.computed(function () {
if (self.hide() == true) {
return '+'
}
return '-';
}, this);
}
function ViewModel() {
var self = this;
this.gpCourseProp = ko.observableArray();
// Fix 1:
// vvvvvvvvvvvvvvvvvvvvvvv v
self.gpCourseProp.push(new gpCourseProperties("MATH1030", true));
self.gpCourseProp.push(new gpCourseProperties("MATH1006", true));
self.gpCourseProp.push(new gpCourseProperties("MATH1046", true));
for (i = 0; i < self.gpCourseProp().length; i++) {
// Fix 2:
// vv
if (self.gpCourseProp()[i].gpCode() == "MATH1030") {
self.gpCourseProp()[i].addCourse("1", "MATH1030", "Calculus", "City1");
self.gpCourseProp()[i].addCourse("2", "MATH1030", "Calculus", "City2");
self.gpCourseProp()[i].addCourse("3", "MATH1030", "Calculus", "City3");
}
if (self.gpCourseProp()[i].gpCode() == "MATH1006") {
self.gpCourseProp()[i].addCourse("4", "MATH1006", "Linear algebra", "City1");
self.gpCourseProp()[i].addCourse("6", "MATH1006", "Linear algebra", "City2");
}
if (self.gpCourseProp()[i].gpCode() == "MATH1046") {
self.gpCourseProp()[i].addCourse("5", "MATH1046", "Discrete Math", "City1");
self.gpCourseProp()[i].addCourse("7", "MATH1046", "Discrete Math", "City2");
}
}
}
var vm = new ViewModel();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Course Code</th>
<th>Course Title</th>
<th>Course Campus</th>
</tr>
</thead>
<tbody data-bind="foreach: gpCourseProp">
<tr class="table-dark">
<td></td>
<td><span data-bind="text: gpCode"></span></td>
<td><span></span></td>
<td></td>
</tr>
<!-- ko foreach: courses -->
<tr data-bind="css: { mutated: $parent.hide() == true }">
<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>