AngularJs e CSS table striped in dinamic grid - javascript

I would like to know in this situation, how to leave a table-striped where I have a group and a sub-group
the result is that some lines are duplicating the color, I would like to know how can I solve this problem?
html
<tbody ng-repeat="a in group">
<tr ng-class-odd="'striped'">
<td>{{a.Name}}</td>
<td></td>
</tr>
<tr ng-repeat="x in records" ng-class-odd="'striped'">
<td>{{x.Name}}</td>
<td>{{x.Country}}</td>
</tr>
</tbody>
script:
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.records = [
{
"Name" : "Alfreds Futterkiste",
"Country" : "Germany"
},
{
"Name" : "Berglunds snabbköp",
"Country" : "Sweden"
},
{
"Name" : "Centro comercial Moctezuma",
"Country" : "Mexico"
},
{
"Name" : "Ernst Handel",
"Country" : "Austria"
}
],
$scope.group = [
{
"Name" : "A"
},
{
"Name" : "B"
},
{
"Name" : "C"
},
{
"Name" : "D"
}
]
});
image for results
ng-style: Created a function in the controller receiving $index and $parent.$index but for some reason it duplicated and repeated the loop.
tbody tr:nth-child(even): duplicating the color;
tbody tr:nth-child(odd): duplicating the color;
$first%2 === 0 , $last%2 === 0 , $even , $odd.
unsuccessfully.

ngRepeat creates a new scope anytime it is used. You are looking for the $even or $odd of the parent repeater when applying a striped class to the row. You can do this by using $parent in the attributes of <tr> or anywhere inside.
Something like this:
<tbody ng-repeat="a in group">
<!-- Always first, so always odd -->
<tr class="striped">
<td>{{a.Name}}</td>
<td></td>
</tr>
<!-- offset by static row above, so invert to use even -->
<tr ng-repeat="x in records" ng-class="{'striped':$parent.$even}">
<td>{{x.Name}}</td>
<td>{{x.Country}}</td>
</tr>
</tbody>

Related

how to give fixed table rows using typescript

I am using table for showing the datas and for data I am using Api.
Api data looks like::
{
"data": [
{
"id": "1",
"name": "name1",
"label": "label1"
},
{
"id": "2",
"name": "name2",
"label": "label2"
},
{
"id": "3",
"name": "name3",
"label": "label3"
}
]
}
html code
<table class="table table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Label</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of sample;">
<td>{{data.id}}</td>
<td>{{data.name}}</td>
<td>{{data.label}}</td>
<tr>
<tbody>
<table>
I need the 10 table rows statically(fixed). The table data is from API. For exanple ,Api contains 2 data... Then UI table should be with 2 rows of data and balance with emply rows... but there should display 10 rows(Mandatory)
which means in UI i want 10 rows with data from Api and balance should be empty.
You can fix in view layer, ts layer or even backend API layer (Not really recommended).
In view layer if you loop over your data, you can calculate if your data's size goes over arbitrary threshold and if not loop again to display as many empty rows as possible.
In ts layer, when you receive data from api you can modify variable you pass to your view by adding to an array as many empty items as you need.
What's important if you use null, then you have to check for it with for example elvis operator.
I would advise agains adding to an array an object with all properties set to null, because then these are not so easily distinguishable from valid data from API and you can for instance make some rows interactive, even though they should not be.
const dataFromApi = [{ "id": "1", "name": "name1" }, { "id": "2", "name": "name2" }]
const minRowsNumber = 10;
const diff = minRowsNumber - dataFromApi.length;
const viewTableData = diff > 0 ? dataFromApi.concat(new Array(diff).fill(null)) : dataFromApi;
console.log(viewTableData)
Example in AngularJs (No Angular in SO Snippets, but it is the same principle)
angular.module('example', [])
.controller('ExampleController', function ExampleController() {
const dataFromApi = [{ "id": "1", "name": "name1" }, { "id": "2", "name": "name2" }]
const minRowsNumber = 10;
const diff = minRowsNumber - dataFromApi.length;
this.viewTableData = diff > 0 ? dataFromApi.concat(new Array(diff).fill(null)) : dataFromApi;
});
table {
border-collapse: collapse;
}
td, th {
border: 1px solid black
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="example" ng-controller="ExampleController as example">
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in example.viewTableData track by $index">
<td>{{row ? row.id : ' '}}</td>
<td>{{row ? row.name : ' '}}</td>
</tr>
</tbody>
</table>
</div>

generic function to sort all columns of a table using javascript

I have the following array of objects in my controller
$scope.records = [
{
"fName" : "Alfreds",
"lName" : "Berglunds",
"country" : "Germany",
"age":21
},
{
"fName" : "Berglunds",
"lName" : "Alfreds",
"country" : "Sweden",
"age":22
},
{
"fName" : "Centro",
"lName" : "Ernst",
"country" : "Mexico",
"age":23
},
{
"fName" : "Ernst",
"lName" : "Centro",
"country" : "Austria",
"age":24
}
]
And I am populating a table in my view using the above array
<table ng-controller="myCtrl" border="1">
<th ng-click="sortByFirstName()">First Nmae</th>
<th ng-click="sortByLastName()">Last Name</th>
<th ng-click="sortByCountry()">Country</th>
<th ng-click="sortByAge()">Age</th>
<tr ng-repeat="x in records">
<td>{{x.fName}}</td>
<td>{{x.lName}}</td>
<td>{{x.country}}</td>
<td>{{x.age}}</td>
</tr>
</table>
On click of each column header, I need to sort the records in ascending order and clicking it again should flip the sorting order(descending order). Right now I am using separate functions to sort them. Can anyone suggest a better way to achieve the same? something like using a generic sort function
You can make a generic function with angularjs $filter by passing the sortBy as a parameter to the function
DEMO
var app = angular.module('testApp',[])
app.controller('myCtrl',function($scope,$filter){
$scope.sortBy = function(sortBy){
$scope.records = $filter('orderBy')($scope.records, sortBy);
}
$scope.records = [
{
"fName" : "Alfreds",
"lName" : "Berglunds",
"country" : "Germany",
"age":21
},
{
"fName" : "Berglunds",
"lName" : "Alfreds",
"country" : "Sweden",
"age":22
},
{
"fName" : "Centro",
"lName" : "Ernst",
"country" : "Mexico",
"age":23
},
{
"fName" : "Ernst",
"lName" : "Centro",
"country" : "Austria",
"age":24
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="testApp">
<table ng-controller="myCtrl" border="1">
<th ng-click="sortBy('fName')">First Nmae</th>
<th ng-click="sortBy('lName')">Last Name</th>
<th ng-click="sortBy('country')">Country</th>
<th ng-click="sortBy('age')">Age</th>
<tr ng-repeat="x in records">
<td>{{x.fName}}</td>
<td>{{x.lName}}</td>
<td>{{x.country}}</td>
<td>{{x.age}}</td>
</tr>
</table>
</body>
Use this generic sortBy and pass the property name to it
var sortBy = ( prop ) => $scope.records.sort( function( a, b ){
return typeof a == "number" ? ( a[ prop ] - b[ prop ] ) : a[ prop ].localeCompare( b[ prop ] );
});
For example
sortBy ( "fName" );

Angular JS nested ngRepeat loop how to break after maxRows are crossed the limit?

I have the below json structure stored in resultData:
{
"ParentObjects": [
{
"objId": "A1",
"ChildObjects": [
{
"description": "child object1"
},
{
"description": "child object2"
}
]
},
{
"objId": "A2",
"ChildObjects": [
{
"description": "child object3"
},
{
"description": "child object4"
},
{
"description": "child object5"
}
]
},
{
"objId": "A3",
"ChildObjects": [
{
"description": "child object6"
},
{
"description": "child object7"
}
]
}
]
}
I have 2 ng-repeat in my html as follows:
<table>
<tbody ng-repeat="parentObj in resultData">
<tr ng-repeat="childObj in parentObj.ChildObjects">
<td>{{childObj.description}}</td>
</tr>
</tbody>
</table>
I want to restrict the number of <tr> that will be displayed to 4 irrespective of number of parent and child in them. I know limitTo but it will apply only on inner loop and will not take account previously rendered rows by earlier parent objects.
Is it possible to restrict the rows considering/counting all child objects?
You can limit with limitTo in ng-repeat
<table>
<tbody ng-repeat="parentObj in resultData | limitTo:4">
<tr ng-repeat="childObj in parentObj.ChildObjects ">
<td>{{childObj.description}}</td>
</tr>
</tbody>
</table>
LimitTo will not work here, because each ng-repeat iteration creates a new scope and LimitTo will be restricted to that specific array or list('ChildObjects').
http://plnkr.co/edit/DrJpf4xiPq4AwtMKUQaU
<body ng-app="myApp">
<div ng-controller="myController">
<table>
<tbody ng-repeat="parentObj in resultData.ParentObjects">
<tr ng-repeat="childObj in parentObj.ChildObjects | limitTo:4">
<td>{{childObj.description}}</td>
</tr>
</tbody>
</table>
</div>
</body>
you can achieve this by setting index for each item in childObjects array.
http://plnkr.co/edit/pUQAvjkJXkn4JRBx1efh
<html ng-app="plunker">
<body ng-app="plunker">
<div ng-controller="MainCtrl">
<table ng-init="SetIndex()">
<tbody ng-repeat="parentObj in resultData.ParentObjects">
<tr ng-if="childObj.index < 4" ng-repeat="childObj in parentObj.ChildObjects">
<td>{{childObj.description}}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
$scope.SetIndex = function () {
var item = 0;
angular.forEach($scope.resultData.ParentObjects, function (value, key) {
angular.forEach(value.ChildObjects, function (value1, key) {
value1.index = item;
item = item + 1;
});
});
}

Display data in a table by grouping them horizontally

I have some data that has the following format:
[name:'Name1', speed:'Val1', color:'Val2']
[name:'Name2', speed:'Val4', color:'Val5']
[name:'Name3', speed:'Val6', color:'Val7']
That I want to display in a table like this:
|Name1|Name2|Name3|
______|_____|______
speed |Val1 |Val4 |Val6
color |Val2 |Val5 |Val7
What I tried to do is group my data like this in the controller:
$scope.data = {
speeds: [{
...
},{
...
},{
...
}],
colors: [{
...
},{
...
},{
...
}],
};
But I am not sure what to put inside the empty areas, because all values there represent the values of the 'val1' variable for all Names (Accounts), and my tests until now keep failing.
You can imagine this as some sort of a comparisons matrix, that is used in order to see the all the values of the same variable across different accounts.
How can I represent the data in my model in order for me to successfully display them in a table as explained?
Edit
My difficulty lies in the fact that you create a table by going from row to row, so my html looks something like this:
<table md-data-table class="md-primary" md-progress="deferred">
<thead>
<tr>
<th ng-repeat="header in headers">
{{header.value}}
</th>
</tr>
</thead>
<tbody>
<tr md-auto-select ng-repeat="field in data">
<td ng-repeat="var in field">{{var.value}}</td>
</tr>
</tbody>
</table>
So as you can see I have a loop for each row, and a loop for each value of each row. This would be easier if I wanted to display the data horizontally, but I want the data vertically. So if we where talking about cars, we would have the car models as headers, and their respective characteristics(speed, color, etc) in each row.
If this is your basic structure:
var cols = [{name:'Name1', val1:'Val1', val2:'Val2'},
{name:'Name2', val1:'Val4', val2:'Val5'},
{name:'Name3', val1:'Val6', val2:'Val7'}];
This code
$scope.table = cols.reduce(function(rows, col) {
rows.headers.push({ value: col.name });
rows.data[0].push({ value: col.speed });
rows.data[1].push({ value: col.color });
return rows;
}, {headers:[], data:[[], []]});
will give you this structure for $scope.table:
$scope.table = {
headers : [{
value : "Name1"
}, {
value : "Name2"
}, {
value : "Name3"
}
],
data : [
[{
value : 'val1'
}, {
value : 'val4'
}, {
value : 'val6'
}
],
[{
value : 'val2'
}, {
value : 'val5'
}, {
value : 'val17'
}
]
]
};
<table md-data-table class="md-primary" md-progress="deferred">
<thead>
<tr>
<th ng-repeat="header in table.headers">
{{header.value}}
</th>
</tr>
</thead>
<tbody>
<tr md-auto-select ng-repeat="field in table.data">
<td ng-repeat="var in field">{{var.value}}</td>
</tr>
</tbody>
</table>
You could try this:
HTML
<table ng-app="myTable" ng-controller="myTableCtrl">
<thead>
<tr>
<th ng-repeat="car in cars">{{car.name}}</th>
</tr>
</thead>
<tbody>
<tr>
<td ng-repeat="car in cars">{{car.speed}}</td>
</tr>
<tr>
<td ng-repeat="car in cars">{{car.color}}</td>
</tr>
</tbody>
</table>
JS
angular.module("myTable",[])
.controller("myTableCtrl", function($scope) {
$scope.cars = [
{
name:'Name1',
speed:'Val1',
color:'Val2'
},
{
name:'Name2',
speed:'Val4',
color:'Val5'
},
{
name:'Name3',
speed:'Val6',
color:'Val7'
}
]
});
https://jsfiddle.net/ABr/ms91jezr/

Knockout table bindings with an object

I have a javascript object that I want to bind to a table using KnockoutJS
Here's my object:
var data = {
"Warnings": {
"numbers": 30,
"content": [
{
"number" : 3001,
"description" : "There may be a problem with the device you are using if you use the default profile"
},
{
"number" : 3002,
"description" : "There may be a problem with the device you are using if you don't use the default profile"
}
]
},
"Errors": {
"numbers": 20,
"content": [
{
"number": 1000,
"description": "No network is loaded"
},
{
"number": 1000,
"description": "No network is loaded"
}
]
}
};
ko.applyBindings(data);
Here's my html code:
<table class="table table-hover">
<thead>
<tr>
<th style="width:100px">Numero</th>
<th>Description</th>
</tr>
</thead>
<tbody data-bind="foreach: Warnings.content">
<tr data-bind="foreach: $data">
<td data-bind="text: $data.number"></td>
<td data-bind="text: $data.description"></td>
</tr>
</tbody>
</table>
Here's a JSFiddle: http://jsfiddle.net/etiennenoel/KmKEB/
I really need to use this format for my data Object.
I don't know why I'm not having the Warnings listed in a table since I'm not getting any errors...
You have an extra foreach that is not needed. Simply remove the foreach on your tr. The foreach on your tbody will assign a new value for $data for each tr that is rendered in the loop.

Categories