knockout multiple with bindings - html

I have a page with several view models, and i need to dynamically build out a checkbox grid based on 2 of them.
This code populates the grid based on 1 view model:
<div id="fundingDetailLevels" class="scroll-adjust" data-bind="with: modelOne">
<table class="table table-hover">
<thead>
<tr data-bind="foreach: modelOneArray">
<!-- ko if: $index() == 0 -->
<th></th>
<!-- /ko -->
<th data-bind="text: name" ></th>
</tr>
</thead>
<tbody data-bind="foreach: modelOneArray2">
<tr data-bind="foreach: $parent.modelOneArray" >
<!-- ko if: $index() == 0 -->
<td data-bind="text: $parent.name"></td>
<!-- /ko -->
<td><input type="checkbox"></input></td>
</tr>
</tbody>
</table>
</div>
Which gives me a grid of:
header1 header2
row1 checkbox checkbox
row2 checkbox checkbox
but what I need is something closer to this:
<div id="fundingDetailLevels" class="scroll-adjust" data-bind="with: modelOne, modelTwo">
<table class="table table-hover">
<thead>
<tr data-bind="foreach: modelOneArray">
<!-- ko if: $index() == 0 -->
<th></th>
<!-- /ko -->
<th data-bind="text: name" ></th>
</tr>
</thead>
<tbody data-bind="foreach: modelTwoArray">
<tr data-bind="foreach: $parent.modelOneArray" >
<!-- ko if: $index() == 0 -->
<td data-bind="text: $parent.name"></td>
<!-- /ko -->
<td><input type="checkbox"></input></td>
</tr>
</tbody>
</table>
</div>
but that fails to find modelTwo

If you just make one view model then you can acheive what you are after. Try this:
var baseModel = function () {
var self = this;
self.modelOneArray = ko.observableArray([{ "name": "Jack" }, { "name": "Jimmy" }]);
self.modelTwoArray = ko.observableArray([{ "name": "Jack2" }, { "name": "Jimmy2" }]);
};
var myModel = myModel || {};
myModel = new baseModel();
ko.applyBindings(myModel);
and the html:
<div id="fundingDetailLevels" class="scroll-adjust">
<table class="table table-hover">
<thead>
<tr data-bind="foreach: modelOneArray">
<!-- ko if: $index()==0 -->
<th></th>
<!-- /ko -->
<th data-bind="text: name"></th>
</tr>
</thead>
<tbody data-bind="foreach: modelTwoArray">
<tr data-bind="foreach: myModel.modelOneArray">
<!-- ko if: $index()==0 -->
<td data-bind="text: myModel.modelOneArray().name"></td>
<!-- /ko -->
<td>
<input type="checkbox"></input>
</td>
</tr>
</tbody>
</table>
</div>

Related

Content moves alone - HTML

Can someone explain me why when I toggle the tabs, the content is not aligned horizontally on both tabs?
If you notice, the content table moves to the left when you go to the document.
I can't figure it out why this is happening. Any help?
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<div class="content">
<ul class="nav nav-tabs">
<!-- ngIf: !vm.selectedTicket.customerName1 && !vm.selectedTicket.customerName2 -->
<!-- ngIf: vm.selectedTicket.customerName1 && vm.selectedTicket.customerName2 -->
<li ng-if="vm.selectedTicket.customerName1 && vm.selectedTicket.customerName2" class="ng-scope" style=""><a data-toggle="tab" href="#customer1Content" class="ng-binding" aria-expanded="false"><i class="glyphicon glyphicon-user"></i> Customer 1 Information</a></li>
<!-- end ngIf: vm.selectedTicket.customerName1 && vm.selectedTicket.customerName2 -->
<li class=""><a data-toggle="tab" href="#documentContent" class="ng-binding" aria-expanded="false"><i class="glyphicon glyphicon-file"></i> Document Information</a></li>
</ul>
<div class="tab-content top5">
<!-- ngIf: !vm.selectedTicket.customerName1 && !vm.selectedTicket.customerName2 && vm.selectedTicket.customerName -->
<!-- ngIf: vm.selectedTicket.customerName1 && vm.selectedTicket.customerName2 -->
<div ng-if="vm.selectedTicket.customerName1 && vm.selectedTicket.customerName2" id="customer1Content" class="tab-pane fade ng-scope" style="">
<table class="table ipp-simple-table">
<tbody>
<tr>
<th class="first-no-border ng-binding">Customer Number</th>
<td class="first-no-border ng-binding">333</td>
</tr>
<tr>
<th class="ng-binding">Customer Name</th>
<td class="ng-binding">Name1</td>
</tr>
<tr>
<th class="ng-binding">Birth Date</th>
<td class="ng-binding">08.12.2017</td>
</tr>
<tr>
<th class="ng-binding">Account Number</th>
<td class="ng-binding">123</td>
</tr>
<tr>
<th class="ng-binding">Status</th>
<td>
<!-- ngIf: vm.selectedTicket.status.description == 'New' --><span ng-if="vm.selectedTicket.status.description == 'New'" class="ipp-color ng-scope"><b class="ng-binding">New</b></span>
<!-- end ngIf: vm.selectedTicket.status.description == 'New' -->
<!-- ngIf: vm.selectedTicket.status.description == 'Closed' -->
</td>
</tr>
</tbody>
<tfoot>
<tr>
<th class="ng-binding">Target Ticket
</th>
<td>
<select ng-options="ticket.docid for ticket in vm.tickets" ng-model="vm.selectedTicket" class="ng-pristine ng-untouched ng-valid">
<option label="1" value="object:49">1</option>
<option label="2" value="object:50">2</option>
<option label="3" value="object:51">3</option>
<option label="4" value="object:52">4</option>
<option label="5" value="object:53">5</option>
<option label="6" value="object:54" selected="selected">6</option>
</select>
</td>
</tr>
</tfoot>
</table>
</div>
<!-- end ngIf: vm.selectedTicket.customerName1 && vm.selectedTicket.customerName2 -->
<div id="documentContent" class="tab-pane fade">
<table class="table ipp-simple-table">
<thead>
</thead>
<tbody>
<tr>
<th class="first-no-border ng-binding">Document ID</th>
<td class="first-no-border ng-binding">6</td>
</tr>
<tr>
<th class="ng-binding">Document Date</th>
<td class="ng-binding">05.12.2018</td>
</tr>
<tr>
<th class="ng-binding">Document Type</th>
<td class="ng-binding">9999</td>
</tr>
<tr>
<th class="ng-binding">Description</th>
<td class="w-50 ng-binding">Unkategorisiert</td>
</tr>
</tbody>
<tfoot>
<tr>
<th class="ng-binding">Target Ticket</th>
<td>
<select ng-options="ticket.docid for ticket in vm.tickets" ng-model="vm.selectedTicket" class="ng-pristine ng-untouched ng-valid">
<option label="1" value="object:49">1</option>
<option label="2" value="object:50">2</option>
<option label="3" value="object:51">3</option>
<option label="4" value="object:52">4</option>
<option label="5" value="object:53">5</option>
<option label="6" value="object:54" selected="selected">6</option>
</select>
</td>
</tr>
</tfoot>
</table>
</div>
</div>

Knockout JS inside table collapse two columns depending on visibility

I'm pretty new in Knockout JS binding and I have this table which is supposed to be a row with a single column with the button if the Confirmed text is empty and two separate columns in other way.
Here is what I've tried so far,
<table class="table" id="Mytable" style="table-layout: fixed;">
<tbody data-bind="foreach: info">
<tr>
<td style="vertical-align:middle;">
<button type="button" class="btn2 btn-default" data-bind="click:$root.getClick, trimText:shortName, trimTextLength: 5, css: Confirmed == '' ? colspan='2' : ''">22</button>
</td>
<td style="vertical-align:middle">
<span style="color:green" data-bind="text: Confirmed, visible: Confirmed != ''">10</span>
</td>
</tr>
</tbody>
</table>
but it seems that it doesn't display the info correctly and I don't know what am I doing wrong.
Please be gentle with me, I'm trying to learn from mistakes.
colspan is an attribute, which you set using the attr binding:
data-bind="attr: { 'colspan': Confirmed() ? 1 : 2 }"
In your specific case, I'd use a virtual if binding to switch between the two cases:
<table>
<tbody data-bind="foreach: info">
<tr>
<!-- ko if: Confirmed -->
<td colspan="2">
<button type="button"
data-bind="click:$root.getClick, trimText:shortName, trimTextLength: 5">22</button>
</td>
<!-- /ko -->
<!-- ko ifnot: Confirmed -->
<td></td>
<td>
<span data-bind="text: Confirmed"></span>
</td>
<!-- /ko -->
</tr>
</tbody>
</table>

HTML Table - Nested Table Row using Knockout

I have a JSON object where EntityCode, EntityName, TagName, and TaskName (from TagList) are to be table column headers.
StatusFlagName in TaskRecordList is then to be in a nested row under it's related TaskName. The StatusFlagName values should be directly below the TaskName.
How do I get this working? The StatusFlagName will not display.
var ViewModel = function() {
this.taskRecords = ko.observableArray([
{
EntityCode: "name",
EntityName: "name desc23",
TagName: "L1",
TaskList: [
{
TaskName: "TaskABC",
TaskRecordList: [
{
StatusFlagName: "OK"
},
{
StatusFlagName: "TEST"
}
]
},
{
TaskName: "TaskDEF",
TaskRecordList: [
{
StatusFlagName: "Error"
}
]
}
]
}
]);
};
ko.applyBindings(new ViewModel());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table table-bordered">
<tbody data-bind="foreach: taskRecords">
<tr>
<td data-bind="text: EntityCode"></td>
<td data-bind="text: EntityName"></td>
<td data-bind="text: TagName"></td>
<td></td>
<!--ko foreach: TaskList-->
<td data-bind="text: TaskName">
<table>
<tbody>
<!--ko foreach: TaskRecordList-->
<tr>
<td data-bind="text: StatusFlagName"></td>
</tr>
<!--/ko-->
</tbody>
</table>
</td>
<!--/ko-->
</tr>
</tbody>
</table>
When you use <td data-bind="text: TaskName"> knockout will replace whatever you have inside this tag with the value of TaskName as a text that's why your last nested table is being replaced with TaskName value.
You can add a div or span for TaskName something like below :
<table class="table table-bordered">
<tbody data-bind="foreach: taskRecords">
<tr>
<td data-bind="text: EntityCode"></td>
<td data-bind="text: EntityName"></td>
<td data-bind="text: TagName"></td>
<td></td>
<!--ko foreach: TaskList-->
<td>
<div data-bind="text: TaskName"></div>
<table>
<tbody>
<!--ko foreach: TaskRecordList-->
<tr>
<td data-bind="text: StatusFlagName"></td>
</tr>
<!--/ko-->
</tbody>
</table>
</td>
<!--/ko-->
</tr>
</tbody>
</table>

Knockout: Can't push to observableArray

I've recently started using KnockOut, so I'm very new to this.
I have completed every tutorial on their site, yet can't get this specific thing to work.
I have to arrays, on the left being all the items, on the right being the items you've selected.
Once you click on the item (left table), it should .push to the right table
ViewModel:
var orderedItemsTable = $("form.orderedDataWithoutBatch")
var viewModel = {
//right side
orderedItems: ko.observableArray(),
//Left side
items: ko.observableArray(),
sortColumn: ko.observable(),
total: ko.observable(),
}
request.done(function (data) {
item.addItem = function () {
alert("item clicked, materiaal id: " + this.MateriaalId);//works
alert(this.MateriaalDescription);//works
viewModel.orderedItems.push(this);//doesn't 'work'
}
viewModel.items.push(item);//unrelated to this context
}
I'm assuming it's either in this code here, or I'm not showing it correctly in my html (because I'm not getting any console errors)
HTML (right side)
<form id="OrderedItemsWithoutBatch" class="orderedDataWithoutBatch">
<table class="orderFormArticlesTable" style="width: 47%;float: right; font-size: 9pt;">
<thead>
<tr>
<th>SKU</th>
<th>Product</th>
<th style="width: 15%">Qty</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: orderedItems">
<tr>
<td data-bind="text: MateriaalSku"> </td>
<td data-bind="text: MateriaalDescription"> </td>
<td data-bind="text: MateriaalId"><!-- Quantity--> </td>
<!--<td><input class="orderedQty" style="max-width: 15%" value="1" />[pieces]</td>-->
<td>Remove</td>
</tr>
</tbody>
</table>
I'm not sure I've understood you right, but I'd solve your task this way:
var orderedItemsTable = $("form.orderedDataWithoutBatch")
var viewModel = {
//right side
orderedItems: ko.observableArray(),
//Left side
items: ko.observableArray(),
sortColumn: ko.observable(),
total: ko.observable(),
}
function proscessRequest(item) {
item.addItem = function () {
//alert("item clicked, materiaal id: " + this.MateriaalId);//works
//alert(item.MateriaalDescription);//works
viewModel.orderedItems.push(this);//doesn't 'work'
}
viewModel.items.push(item);//unrelated to this context
}
ko.applyBindings(viewModel);
proscessRequest({MateriaalSku: "M1", MateriaalDescription: "D1", MateriaalId: "1"});
proscessRequest({MateriaalSku: "M2", MateriaalDescription: "D2", MateriaalId: "2"});
proscessRequest({MateriaalSku: "M3", MateriaalDescription: "D3", MateriaalId: "3"});
proscessRequest({MateriaalSku: "M4", MateriaalDescription: "D4", MateriaalId: "4"});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<form id="OrderedItemsWithoutBatch" class="orderedDataWithoutBatch">
<div>Alavilable items:</div>
<div>
<table class="orderFormArticlesTable">
<thead>
<tr>
<th>SKU</th>
<th>Product</th>
<th style="width: 15%">Qty</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: MateriaalSku"> </td>
<td data-bind="text: MateriaalDescription"> </td>
<td data-bind="text: MateriaalId"><!-- Quantity--> </td>
<td><div data-bind="click: addItem">Add</div></td>
</tr>
</tbody>
</table>
</div>
<div style="margin-top: 30px;">
<div>Ordered items:</div>
<table class="orderFormArticlesTable">
<thead>
<tr>
<th>SKU</th>
<th>Product</th>
<th style="width: 15%">Qty</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: orderedItems">
<tr>
<td data-bind="text: MateriaalSku"> </td>
<td data-bind="text: MateriaalDescription"> </td>
<td data-bind="text: MateriaalId"><!-- Quantity--> </td>
<td><div data-bind="click: function() { $parent.orderedItems.remove($data); }">Remove</div></td>
</tr>
</tbody>
</table>
</div>
</form>
Note
I've mocked request with "proscessRequest" function called after bindings have been applied.

header row in knockout

I want to have some HTML like the following:
<table>
<tbody>
<tr data-bind="foreach: foo">
<td>some header</td>
<td data-bind="value: bar"></td>
</tr>
</tbody>
</table>
I want repeated cells generated by a Knockout foreach binding. But how can I do this while having a header cell which I don't want repeated? The desired output, after binding, is something like:
<table>
<tbody>
<tr>
<td>some header</td>
<td>fred</td>
<td>wilma</td>
<td>barney</td>
<td>bam-bam</td>
</tr>
</tbody>
</table>
The same question applies to having a header row. If the foreach binding is on the <tr> element, how do I tell Knockout not to repeat the first row or cell?
You can use the containerless version of the binding ( see in the documentation: Using foreach without a container element section)
<table>
<tbody>
<tr>
<td>some header</td>
<!-- ko foreach: foo -->
<td data-bind="text: bar"></td>
<!-- /ko -->
</tr>
</tbody>
</table>
Demo JSFiddle.
So the same technique can be used if you want to have a fixed header row:
<table>
<tbody>
<tr>
<td>some header</td>
</tr>
<!-- ko foreach: foo -->
<tr>
<td data-bind="text: bar"></td>
</tr>
<!-- /ko -->
</tbody>
</table>
You can use this
<table>
<tbody>
<tr>
<td>Some header</td>
<!-- ko foreach: foo -->
<td data-bind="value: bar"></td>
<!-- /ko -->
</tr>
</tbody>
</table>
To repeat tr you can use same desicion, but it better to use html possibilities
<table>
<thead>
<tr>
<td> Header </td>
</tr>
</thead>
<tbody>
<tr data-bind="foreach: foo">
<td data-bind="text: bar"></td>
</tr>
</tbody>
</table>