loop through observable array of knockout property - javascript

I am using knockout mapping library to bind JSON data from .NET service to a property in KO view model, in which the property has an array of objects that I need to loop through and render on the screen.
The .NET model:
new{
count = count,
total = total,
rows = items,
}
the rows property holds list of objects, which needs to be rendered into a table using KO.
I tired using
<!-- ko foreach: masterData().rows-->
<tr>
<td><span data-bind='text: Id' /></td>
<td><span data-bind='text: Name' /></td>
<td><span data-bind='text: Description' /></td>
<td><span data-bind='text: Status' /></td>
</tr>
<!-- /ko -->
where the masterData is an observable. After data load, it renders nothing inside the table. As a workaround, I have changed the model the observable to observableArray([])
new List<dynamic> {
new
{
count = recCount,
total = total,
rows = items,
}};
and changed the rendering logic to
<!-- ko foreach: masterData -->
<!-- ko foreach: rows-->
<tr>
<td><span data-bind='text: Id' /></td>
<td><span data-bind='text: Name' /></td>
<td><span data-bind='text: Description' /></td>
<td><span data-bind='text: Status' /></td>
</tr>
<!-- /ko -->
<!-- /ko -->
Now it works as expected. There should be a better way of dealing with this or I am missing something I suppose. Also, I needed to loop through this list in order to access other properties.
EDIT 1:
http://jsfiddle.net/krishnasarma/hdt9ehth/

well i tweaked your code little bit to make it ideal . I see not point looping masterData for getting rows data .
we can now use with binding which is perfect for such scenario stated above.
view:
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Status</th>
</tr>
</thead>
<tbody data-bind="with:masterData2">
<!-- ko foreach:rows -->
<tr>
<td><span data-bind='text: Id' /></td>
<td><span data-bind='text: Name' /></td>
<td><span data-bind='text: Description' /></td>
<td><span data-bind='text: Status' /></td>
</tr>
<!-- /ko -->
</tbody>
</table>
viewModel:
var VM = {
masterData: ko.observable([]), //initializing
masterData2: ko.observable([])
}
sample working fiddle here
If you want to in a Lazy Loading way check here

Related

Using knockout if binding inside a table

I was trying to use the if binding inside a table and the 3rd column is not at all displaying the text where as the entries in the 1st column are getting displayed.
<table id="searchPanelForm" cellspacing="0" cellpadding="0" align="center" class="conttable" width="100%" border="0" data-bind="">
<tbody>
<!-- ko foreach: searchPanelArray -->
<!-- ko if: $parent.isSearchEven($data.id) -->
<tr>
<td class="col2" data-bind="text: $data.label"></td>
<td class="col3"><input type="text"></td>
<!-- /ko -->
<!-- ko if: !$parent.isSearchEven($data.id) -->
<td class="col2" data-bind="text: $data.label"></td>
<td class="col3"><input type="text"></td>
</tr>
<!-- /ko -->
<!-- /ko -->
</tbody>
</table>
searchPanelArray is populated through an ajax call and isSearchEven returns true or false when the index is even or odd respectively.
Knockout expects "containerless control flow syntax" to act like elements. They cannot start on the outside of an element and end inside the element. So from Knockout's point of view, the comments internal to <tr> are simply malformed and ignored. So this is what it looks like for Knockout:
<!-- ko foreach: searchPanelArray -->
<!-- ko if: $parent.isSearchEven($data.id) -->
<tr>
<td class="col2" data-bind="text: $data.label"></td>
<td class="col3"><input type="text"></td>
<td class="col2" data-bind="text: $data.label"></td>
<td class="col3"><input type="text"></td>
</tr>
<!-- /ko -->
<!-- /ko -->
Logically, you want to group every two items in your array. You should create a computed observable the returns a new array with the two items grouped together.
this.searchPanelArrayGrouped = ko.pureComputed(function() {
var result = [], source = this.searchPanelArray();
for (var i = 0; i < source.length; i += 2) {
if (i + 1 >= source.length) {
result.push({left: source[i], right: {}});
} else {
result.push({left: source[i], right: source[i+1]});
}
}
return result;
}, this);
Html:
<!-- ko foreach: searchPanelArrayGrouped -->
<tr>
<td class="col2" data-bind="text: $data.left.label"></td>
<td class="col3"><input type="text"></td>
<td class="col2" data-bind="text: $data.right.label"></td>
<td class="col3"><input type="text"></td>
</tr>
<!-- /ko -->
https://jsfiddle.net/bg75xvxc/
Here is a related answer: https://stackoverflow.com/a/10577599/1287183

If statement in knockout.js not working as expected

I'm trying to display the string "No data was found." inside a table row whenever the data array is empty, but it seems the message get always printed no matter what.
Reproduction online (ignoring the condition orders.length ==0)
What am I doing wrong?
<table>
<thead>
<tr>
<th>Truck</th>
<th>Pickup</th>
</tr>
</thead>
<!-- ko if: orders.length==2 -->
<tbody>
<tr colspan="2">No data was found.</tr>
</tbody>
<!-- /ko -->
<tbody data-bind="foreach: orders">
<tr>
<td data-bind="text: truck"></td>
<td></td>
</tr>
</tbody>
</table>
If your orders is an ko.observableArray you need to write orders() to get the underlying array and get the length from there:
<!-- ko if: orders().length== 0 -->
Your HTML also invalid, the td elements are missing from:
<!-- ko if: orders().length==0 -->
<tbody data-bind="if: orders().length==0">
<tr colspan="2"><td>No data was found.</td></tr>
</tbody>
<!-- /ko -->
Demo JSFiddle.

Why the pagination of footable is not working?

I'm trying to implement FooTable-2 in my project, but for some reason I can't get the pagination working.
I'm following THIS tutorial and here is what I have so far as a table code:
<div id="mainContent">
<div id="allTrackersDiv" style="display: none;">
<label><b>Active Trackers</b></label>
<table class="activeTrackersTable" id="allTrackersTable"
data-page-navigation=".pagination">
<thead>
<tr>
<th> ID </th>
<th> col 1 </th>
<th> col 2 </th>
<th> col 3 </th>
</tr>
</thead>
<tbody data-bind="foreach: trackersObjArray">
<tr data-bind="click: test">
<td><span data-bind="text: tId"></span></td>
<td><span data-bind="text: tname"></span></td>
<td><span data-bind="text: pname"></span></td>
<td><span data-bind="text: tcreate"></span></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<div class="pagination"></div>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
The problem is that the paging is not working. I have 22 records in my table and it is supposed to start paging after the 10th record
Here is how it looks:
What am I missing here? At my point of view everything looks pretty fine. What am I missing, I really can't understand my mistake.
You can try mentioning
data-page-size="10"
explicitly.
And if that doesn't work, may be issue is due to dynamic data being added to footable.
Use
$('#myTable').append(html).trigger('footable_redraw');
So that footable will be redrawed and size limit will be applied.
Reference links: Footable data page size not respected and
Other issues due to dynamic data in footable

Knockout.js -- understanding foreach and with

I've been going through the learn.knockout.js tutorials and been experimenting. Can someone explain why this works [Tutorial: Single page applications, Step 2] (using with: chosenFolderData and foreach: mails):
<!-- Mails grid -->
<table class="mails" data-bind="with: chosenFolderData">
<thead><tr><th>From</th><th>To</th><th>Subject</th><th>Date</th></tr></thead>
<tbody data-bind="foreach: mails">
<tr>
<td data-bind="text: from"></td>
<td data-bind="text: to"></td>
<td data-bind="text: subject"></td>
<td data-bind="text: date"></td>
</tr>
</tbody>
</table>
but not this (using just foreach: chosenFolderData.mails):
<!-- Mails grid -->
<table class="mails">
<thead><tr><th>From</th><th>To</th><th>Subject</th><th>Date</th></tr></thead>
<tbody data-bind="foreach: chosenFolderData.mails">
<tr>
<td data-bind="text: from"></td>
<td data-bind="text: to"></td>
<td data-bind="text: subject"></td>
<td data-bind="text: date"></td>
</tr>
</tbody>
</table>
I suspect it's because while chosenFolderData is observable, chosenFolderData.mails is not. Can anyone tell me for certain?
Many thanks!
-- Ralph
Because you are not actually accessing the property you want with the way it is written. In the model chosenFolderData is an observable and must be called like a method to retrieve the value. To provide the functionality without using with (and I suggest not using with where high performance is necessary because of the overhead)...
<tbody data-bind="foreach: chosenFolderData().mails">

Knockout.js dynamic composable table

I'm trying to make a "dynamic table" with knockout js and I'm having a bit of difficulty. I want to have a "Common Row Template" with a nested template for the variable columns. Something like this:
<script type="text/x-jquery-tmpl" id="CommonRow">
<td><input type="text" data-bind="value: Nome" /></td>
<td data-bind="template: { name: $item.LabelOne + 'Row' }"></td>
<td><button class="fancybox edit" data-bind="click: Edit">Modifica</button></td>
<td><button class="remove" data-bind="click: Remove">Rimuovi</button></td>
</script>
So the second <td> will render a template, which will look like this:
<script type="text/x-jquery-tmpl" id="ScalaRow">
<td><input type="text" data-bind="value: PianiFuoriTerra" /></td>
<td><input type="text" data-bind="value: Foo" /></td>
</script>
This "works" but it has a big problem: the desired <td> are nested in the outer <td> with the template binding, causing improper alignment with the header (which also is structured the same way).
I tried using the {{tmpl}} syntax to avoid the wrapping <td> and this gets me the right html, but all the databinding and observable don't work anymore in the dynamic part.
Is there a way to render a block of <td> preserving the knockout observable functionality and avoiding any wrapping tag? Thanks.
Your best option is to look at using KO 1.3 beta. Here is a sample of doing something like what you want: http://jsfiddle.net/rniemeyer/wmDfv/
<table data-bind="foreach: items">
<tr>
<td data-bind="text: name"></td>
<!-- ko template: type -->
<!-- /ko -->
</tr>
</table>
<script id="typeA" type="text/html">
<td>typeA template</td>
</script>
<script id="typeB" type="text/html">
<td>typeB template</td>
</script>

Categories

Resources