knockout.js nested foreach referencing each other - javascript

I'm trying to fill in the rows and cells of my table like the following:
<tbody data-bind="foreach: {data: rows, as: 'row'}">
<tr data-bind="foreach: {data: row, as: 'cell'}">
<td data-bind="text: cell"></td>
</tr>
</tbody>
with this as my rows var:
self.rows = ko.observableArray([
[
['Test', '10', '100', '98', '10', '15']
],
[
['Test2', '10', '100', '98', '10', '20']
]
]);
This fills in the correct number of rows, but only the first TD is populated with the entire contents of the array.
results in:
<tbody data-bind="foreach: {data: rows, as: 'row'}">
<tr data-bind="foreach: {data: row, as: 'cell'}">
<td data-bind="text: cell">Test,10,100,98,10,15</td>
</tr>
<tr data-bind="foreach: {data: row, as: 'cell'}">
<td data-bind="text: cell">Test2,10,100,98,10,20</td>
</tr>
</tbody>
What am I doing wrong?

You have three levels of arrays and you're only iterating two levels deep. If you change your rows data to nest only two levels deep, it should work as expected:
self.rows = ko.observableArray([
[
'Test', '10', '100', '98', '10', '15'
],
[
'Test2', '10', '100', '98', '10', '20'
]
]);
JSFiddle: http://jsfiddle.net/Zj2qN/

You have a 3rd level array. Are you sure you need that?
If so you to need nest one more foreach binding.
I dont think so, I think you want your array look this way:
self.rows = ko.observableArray([[1,2,3],[4,5,6]]);

Related

How to remove default order of ng-repeat

How do I stop default sorting inside the ng-repeat for dynamic table data ?
Currently I am getting below order:
Addr | CustomerId | Name
but what I want is below ordering:
CustomerId | Name | Addr
Any Help would me much appreciated.
JS:
app.controller('MyController', function ($scope) {
$scope.Customers = [
{ CustomerId: 1, Name: "John Hammond", Addr:'India'
},
{
CustomerId: 2, Name: "Mudassar Khan", Addr:'India'
},
{
CustomerId: 3, Name: "Suzanne Mathews", Addr:'India'
},
{
CustomerId: 4, Name: "Robert Schidner", Addr: 'India'
}
];
});
HTML:
<table>
<tr >
<th ng-repeat="(key,value) in Customers[0]">{{key}}</th>
</tr>
<tbody ng-repeat="c in Customers">
<tr>
</tr>
</tbody>
</table>
Try this below way. I hope this below snippet result is showing what you want.
angular.module("aaa",[]).controller('MyController', function ($scope) {
$scope.Customers = [
{ CustomerId: 1, Name: "John Hammond", Addr:'India'
},
{
CustomerId: 2, Name: "Mudassar Khan", Addr:'India'
},
{
CustomerId: 3, Name: "Suzanne Mathews", Addr:'India'
},
{
CustomerId: 4, Name: "Robert Schidner", Addr: 'India'
}
];
$scope.keys = Object.keys($scope.Customers[0]);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="aaa" ng-controller="MyController">
<table>
<tr>
<th ng-repeat="key in keys">
{{key}}
</th>
</tr>
<tbody ng-repeat="c in Customers">
<tr>
<td ng-repeat="key in keys">{{c[key]}}</td>
</tr>
</tbody>
</table>
</div>
So objects in JS are inherently unordered. What you can do is just hard code the keys in the header if that will be fixed for that particular table and then print the values in the respective order.
Something like this:
<table>
<tr >
<th>CustomerId</th>
<th>Name</th>
<th>Addr</th>
</tr>
<tbody>
<tr ng-repeat="c in Customers">
<td>{{CustomerId}}</td>
<td>{{Name}}</td>
<td>{{c.Addr}}</td>
</tr>
</tbody>
</table>
Note: I put the ng-repeat on the tr which is probably what you need. I dont think you should put it on the tbody.
Do you mean the sort order of the data or the display order of the columns?
The accepted answer displays the data by the order of the columns as specified, but if you want the data itself sorted then just add a filter to the data like this:
<tbody ng-repeat="c in Customers|orderBy:['CustomerId','Name','Addr']">
This sorts the actual data in the list by the fields specified.

Hide/show table rows based on checkbox

I have some checkboxes which I'd like to use to show/hide rows in a table whose contents match the values of the checkbox which is selected.
Checkboxes:
<input type='checkbox' name='foo1' value='foo1' v-model="selectedType"/> foo1
<input type='checkbox' name='foo2' value='foo2' v-model="selectedType"/> foo2
<input type='checkbox' name='bar1' value='bar1' v-model="selectedType"/> bar1
I have an object which I used to construct a table using v-for:
<table>
<template v-for="sampleItem in sampleObj">
<tr>
<td>{{sampleItem.item}}</td>
<td>{{sampleItem.description}}</td>
</tr>
</template>
</table>
JS:
new Vue({
data: {
selectedType: [],
sampleObj = [{'item': 'item1', 'description': 'foo1 blah'},
{'item': 'item2', 'description': 'foo2 vlah'},
{'item': 'item3', 'description': 'bar1 nlah'},
{'item': 'item4', 'description': 'bar2 clah'},
];
}
});
By default, the checkboxes are unchecked. So, only the row which has a cell with description 'bar2' is initially visible. Then when I toggle the other checkboxes, the other rows should also become visible (the descriptions don't match the checkbox values verbatim but has a few words following it. I can do some string processing here).
I thought I could use the v-if directive in the tag to look at value of selectedType, but I am not sure how I can accomplish this.
Pseudo-code:
<tr v-if="selectedType ~= /sampleItem.description/">
...
...
</tr>
How could I accomplish this?
You actually have two conditions you need for the v-if: if there is no checkbox matching the description, you want the row to display; if there is a checkbox, it has to be checked.
I put the checkbox values into data, where they belong. I made a method for the test. It first looks to see whether the description matches any checkbox value, then it checks whether the matched value is selected.
new Vue({
el: '#app',
data: {
selectedType: [],
sampleObj: [{
'item': 'item1',
'description': 'foo1 blah'
},
{
'item': 'item2',
'description': 'foo2 vlah'
},
{
'item': 'item3',
'description': 'bar1 nlah'
},
{
'item': 'item4',
'description': 'bar2 clah'
},
],
cbValues: ['foo1', 'foo2', 'bar1']
},
methods: {
isVisible(row) {
const matchedValue = this.cbValues.find(v => row.description.indexOf(v) >= 0);
if (!matchedValue) {
return true;
}
return this.selectedType.includes(matchedValue);
}
}
});
td {
border: thin solid black;
}
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<div v-for="val in cbValues">
<label>
<input type='checkbox' :value='val' v-model="selectedType">
{{val}}
</label>
</div>
<table>
<template v-for="sampleItem in sampleObj">
<tr v-if="isVisible(sampleItem)">
<td>{{sampleItem.item}}</td>
<td>{{sampleItem.description}}</td>
</tr>
</template>
</table>
</div>

different table rows per data in ng-repeat Angular

Okay, so I'm having hard time understanding how ng-repeat builds tables. What I'm trying to do is that per row, there is customer name and address. I can't get it to work. Here is my HTML code:
<table class="table table-striped" ng-controller="myController">
<thead>
<tr>
<th>Company Name</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="company in fieldData" row-id="{{ company.name }}">
<td>{{ company.name }}</td><td>{{ company.address }}</td>
</tr>
</tbody>
</table>
and here is my script:
var companyName = [];
var companyAddress = [];
$scope.fieldData = [];
$(data).find('record').each(function () {
companyName.push($(this).record(6));
companyAddress.push($(this).record(47));
});
$scope.fieldData.push({
name: companyName,
address: companyAddress
})
So, in companyName and companyAddress arrays, there are name and addresses being stored. But I can't get one company & address per row. Any ideas?
You built an one element array with one object of two arrays, like:
fieldData: [
{
name: [
'name1', 'name2', 'etc'
],
address: [
'addr1', 'addr2', 'etc'
]
}
]
You want to have an array of objects with name and address fields:
fieldData: [
{
name: 'name1',
address: 'addr1'
},
{
name: 'name2',
address: 'addr2'
},
{
name: 'etc',
address: 'etc'
}
]
To achieve that, go with:
$scope.fieldData = [];
$(data).find('record').each(function (item) {
$scope.fieldData.push({
name: item.record(6),
address: item.record(47)
});
});

AngularJS: How to make this table with Ng-repeat?

Please, how can we make the table below with ng-repeat? I do not have permission to change the json structure, so I have to use exactly this way.
My json:
$scope.carCollection = {
'Toyota': [
{
'model': 'Corolla',
'price': '20.000,00',
'tag': ['a', 'b']
},{
'name': 'Hilux',
'price': '31.000,00',
'tag': ['b', 'c']
}
],
'Honda': [
{
'model': 'Civic',
'price': '18.000,00',
'tag': ['c']
}
]
};
And this is the html table:
<table>
<tr>
<td>Producer</td>
<td>Model</td>
<td>Price</td>
<td>Tags</td>
</tr>
<tr>
<td>Toyota</td>
<td>Corolla</td>
<td>20.000,00</td>
<td>a b</td>
</tr>
<tr>
<td>Toyota</td>
<td>Hilux</td>
<td>31.000,00</td>
<td>b c</td>
</tr>
<tr>
<td>Honda</td>
<td>Civic</td>
<td>18.000,00</td>
<td>c</td>
</tr>
</table>
Thanks!!!
You can find the ng-repeat documentation
https://docs.angularjs.org/api/ng/directive/ngRepeat
$scope.friends =
[{name:'John', phone:'555-1212', age:10},
{name:'Mary', phone:'555-9876', age:19},
{name:'Mike', phone:'555-4321', age:21},
{name:'Adam', phone:'555-5678', age:35},
{name:'Julie', phone:'555-8765', age:29}];
<div ng-controller="ExampleController">
<table class="friend">
<tr>
<th>Name</th>
<th>Phone Number</th>
<th>Age</th>
</tr>
<tr ng-repeat="friend in friends">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
<td>{{friend.age}}</td>
</tr>
</table>
You can format your data into your controller before render it in your view. Moreover, in my example you will see the :: bindings.
This is the one-time binding, it will stop recalculating the expression once they are stable, so you can improve your page loading by reducing numbers of watchers.
Controller
(function(){
function Controller($scope) {
$scope.carCollection = {
'Toyota': [
{
'model': 'Corolla',
'price': '20.000,00',
'tag': ['a', 'b']
},{
'model': 'Hilux',
'price': '31.000,00',
'tag': ['b', 'c']
}
],
'Honda': [
{
'model': 'Civic',
'price': '18.000,00',
'tag': ['c']
}
]
};
//To format our data
function format(data){
//Return a flatten array
return [].concat.apply([], Object.keys(data).map(function(key){
//Map our data object
return data[key].map(function(elm){
//Add brand property with the current key
elm.brand = key;
//Join tag array value
elm.tag = elm.tag.join(' ');
return elm;
});
}));
}
//Apply our format function
$scope.carCollection = format($scope.carCollection);
}
angular
.module('app', [])
.controller('ctrl', Controller);
})();
Then, you will get a flat array, so you just can iterate over it.
HTML
<body ng-app='app' ng-controller='ctrl'>
<table>
<tr>
<td>Producer</td>
<td>Model</td>
<td>Price</td>
<td>Tags</td>
</tr>
<tr ng-repeat="item in ::carCollection">
<td>{{::item.brand}}</td>
<td>{{::item.model}}</td>
<td>{{::item.price}}</td>
<td>{{::item.tag}}</td>
</tr>
</table>
</body>
You can see the Working Plunker

How to populate data in table element?

I am trying to display table data within Angular framework
In my html
<table class='table'>
<tr>
<th ng-repeat='test in tests'>{{test.name}}</th> // it shows correctly...
</tr>
<tr ng-repeat=''> //not sure what to do here...
<td>Item</td><td>Item</td><td>Item</td><td>Item</td>
</tr>
</table>
controller
.controller('BoxCtrl', ['$scope', function ($scope) {
$scope.tests = [
{'name':'header1',
'items':
[
{'name':'Item 1', 'link':'1'},
{'name':'Item 2', 'link':'2'},
{'name':'Item 3', 'link':'3'}
]
},
{'name':'header2',
'items':
[
{'name':'Item 1', 'link':'i1'},
{'name':'Item 2', 'link':'i2'}
]
},
{'name':'header3',
'items':
[
{'name':'Item 1', 'link':'i1'},
{'name':'Item 2', 'link':'i2'}
]
},
{'name':'header4',
'items':
[
{'name':'Item 1', 'link':'I1'},
{'name':'Item 2', 'link':'I2'},
{'name':'Item 3', 'link':'I3'}
]
}
];
}]);
I have no problem display data in TH but not sure how to apply hg-repeat in the tr and td. Can anyone give me a hint for this? Thanks a lot!
You can do something like this:
Example:
<div ng-app="App" ng-controller="ctrl" >
<table class='table'>
<tr>
<th ng-repeat='test in tests'>{{test.name}}</th>
</tr>
<tr ng-repeat='itemsColl in tests'>
<td ng-repeat="item in itemsColl.itemsRow">{{item.name}}</td>
</tr>
</table>
</div>
live Example: http://jsfiddle.net/choroshin/4mD86/
also in this stackoverflow answer you can find more information on dynamic table creation

Categories