Reputation: 21
Edit:
I need to make a table that prints rows of observable array object attributes.
So, each job can have an array of tasks. I have input boxes to add jobs and tasks to dropdown menus and a submit button to add the selected task to the selected job. This all works fine. I've checked and the tasks are being pushed into their respective job object task arrays.
Edit: I check viewModel.jobs()[0].tasks() in the console and it shows the tasks being added correctly.
Then I want to show the results in a table using nested templates (above)
Edit: I began by using this method of simply nesting foreaches in the table and assuming the parent child hierarchy would work. Clearly the mistake is in my JavaScript, but the tasks still won't show up and I'm all jammed up... Thank you guys so much for the help!
var job = function(name) {
this.jobName = name;
this.tasks = ko.observableArray();
}
var task = function(name) {
this.taskName = name;
}
var viewModel = {
selectedJob: ko.observable(),
selectedTask: ko.observable(),
jobName: "",
jobs: ko.observableArray([new job("job1")]),
taskName: "",
taskList: ko.observableArray([new task("task1")]),
addJob: function() {
var objectToAdd = new job(this.jobName);
if (objectToAdd.jobName === "") return;
for (var i = 0; i < this.jobs().length; i++) {
if (objectToAdd.jobName === this.jobs()[i].jobName) {
return;
}
}
this.jobs.push(objectToAdd);
},
addTask: function() {
var taskToAdd = new task(this.taskName);
if (taskToAdd.taskName === "") return;
for (var i = 0; i < this.taskList().length; i++) {
if (taskToAdd.taskName === this.taskList()[i].taskName) {
return;
}
}
this.taskList.push(taskToAdd);
},
removeJob: function(job) {
viewModel.jobs.remove(job);
},
submitTask: function() {
this.selectedJob().tasks().push(this.selectedTask());
},
}
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form data-bind="submit: submitTask">
<div class="form-element-container">
<span>
<select data-bind="options: jobs, optionsText: 'jobName', value: selectedJob, optionsCaption: 'Select Job'"></select>
<input class="text-box" data-bind="value: jobName" /><button data-bind="click: addJob">Add Job</button>
</span>
</div>
<div class="form-element-container">
<span>
<select data-bind="options: taskList, optionsText: 'taskName',
value: selectedTask, optionsCaption: 'Select Task'"></select>
<input class="text-box" data-bind="value: taskName" /><button data-bind="click: addTask">Add Task</button>
</span>
</div>
<div class="form-element-container">
<button class="submit-button" data-bind="click: submitTask">Add to Timesheet</button>
</div>
</form>
<div class="table-container">
<h2>Timesheet:</h2>
<table class="table">
<tbody data-bind="foreach: jobs">
<tr>
<th>
<span data-bind="text: jobName"></span>
</th>
<th>Hours</th>
</tr>
<tr data-bind="foreach: tasks">
<td>
<span data-bind="text: taskName"></span>
</td>
</tr>
</tbody>
</table>
</div>
Upvotes: 0
Views: 336
Reputation: 2744
What @Adrian suggested should work. It can also be achieved in much simpler code
var job = function(name) {
this.jobName = name;
this.tasks =[
new task("job1"),
new task("job2")
]
}
var task = function(name) {
this.taskName = name;
}
var VM = function(){
this.jobs = [
new job("Dev"),
new job("Tester")
]
}
ko.applyBindings(new VM());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<table class="table">
<tbody data-bind="foreach: jobs">
<tr>
<th>
<span data-bind="text: jobName"></span>
</th>
<th>Hours</th>
</tr>
<tr data-bind="foreach: tasks">
<td >
<span data-bind="text: taskName"></span>
</td>
</tr>
</tbody>
</table>
Upvotes: 0
Reputation: 1587
You cannot put div
directly inside a table
element. That's why it is ignored.
Change this <div data-bind="template: {name: 'tasksTemplate', foreach: tasks}"></div>
to a <tr>
and modify the template to be a td
.
Also this part might be a typo: <td data-bind="taskName"></td>
.
var job = function(name) {
this.jobName = name;
this.tasks = ko.observableArray([
new task("job1"),
new task("job2")
]);
}
var task = function(name) {
this.taskName = name;
}
var VM = function(){
this.jobs = [
new job("Dev"),
new job("Tester")
]
}
ko.applyBindings(new VM());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table">
<tbody data-bind="template: {name: 'jobsTemplate', foreach: jobs}">
</tbody>
</table>
<script type="text/html" id="jobsTemplate">
<tr>
<th>
<span data-bind="text: jobName"></span>
<a class="badge badge-pill danger" data-bind="click: $root.removeJob">remove</a>
</th>
<th>Hours</th>
</tr>
<tr data-bind="template: {name: 'tasksTemplate', foreach: tasks}"></tr>
</script>
<script type="text/html" id="tasksTemplate">
<td data-bind="text: taskName"></td>
</script>
Also, you might want to use the snippet feature of SO, so that your code will be runnable.
Upvotes: 1