Knockout.js dynamic composable table - javascript

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>

Related

Multidimensional Array printing in knockout with functionality over each row through click button

I am able to create an array called columns which has the following structure:
columns = [
{column: [1,2,3,4,5,6]},
{column: [7,8,9,10,11,12]},
{column: [13,14,15,16,17,18]}
]
I successfully print the array using the following code:
<table class="table">
<tbody data-bind="foreach: columns">
<tr data-bind="foreach: $data.column">
<td><input type="button" class="btn btn-default" data-bind="value: $data"</td>
</tr>
</tbody>
</table>
However I want at the end of each table row to introduce a button to be able to delete this row. I know that the button would contain a data-bind click function called removeColumn and in my view model it will be something like this:
self.removeColumn = function() {
self.columns.remove(this);
}
I can't find a way to introduce this button correctly in my table. Other times it's created 6 times in every row and other times it doesn't apper at all. The same thing happens when I try to show the index of every column - table row so that I can count how many columns appear.
https://jsfiddle.net/qmxs87k5/4/
You can try using the comment syntax for knockout's foreach so you can add another <td> per row:
<table class="table">
<tbody>
<!-- ko foreach: columns -->
<tr>
<!-- ko foreach: $data.column -->
<td><input type="button" class="btn btn-default" data-bind="value: $data"</td>
<!-- /ko -->
<td>
<div class="btn btn-primary" data-bind="click: $parent.deleteRow">Delete Row</div>
</td>
</tr>
<!-- /ko -->
</tbody>
</table>

loop through observable array of knockout property

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

How to bind server generated html data into knockout model attribute?

I want to bind back server generated html into knockout model. Is there any manner to do it?
<table>
<tr data-bind="with: dataList">
<td data-bind="text: Name">
Name
</td>
<td data-bind="text: Text">
Text
</td>
</tr>
<tr data-bind="with: dataList">
<td data-bind="text: Name">
Name2
</td>
<td data-bind="text: Text">
Text2
</td>
</tr>
</table>
Stuff like this...
The dataList property of the object you bound to view will contain all the data you are expecting.
You should use ko.mapping.toJS() to convert an observable view model to a raw view model.

Change tr color when checkbox checked

I have created table like below:
<table data-bind="with: choosenDateGoal">
<tbody data-bind="foreach: tblGoals">
<!-- ko if: status -->
<tr class="success">
<td>
<input type="checkbox" onclick="this.disabled = 'disabled';" data-bind="checked: status, disable: status, click: $root.UpdateStatus" />
</td>
<td>
<span style="width: 80%" data-bind="text: goals" />
</td>
<td>
<input type="text" style="width: 80%" data-bind="value: notes , event: { blur: $root.UpdateNote}" />
</td>
</tr>
<!-- /ko -->
</tbody>
</table>
I have an checkbox in every row and when i click on it it should change the row color.
But not working. here is my script for changing color:
self.UpdateColor = function ChangeBackgroundColor() {
debugger;
if ($("input[type='checkbox']:checked")) {
$(this).parent().addClass('success'); ;
}
};
Use knockout's css binding - see http://knockoutjs.com/documentation/css-binding.html
Try binding below and you don't call the ChangeBackgroundColor function
<tr data-bind="css: {success: status()}">
Zaik's answer will work, but if you do it the knockout way, you don't need to add any JavaScript eventing code. This is one of the real benefit's of knockout.

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">

Categories

Resources