AngularJS - Sorting data ascending / descending when column is clicked - javascript

I have the following view code:
<tr ng-repeat="c in clients | orderBy:'code'">
<td>{{c.firstname}} {{c.lastname}}</td>
<td>{{c.telephone}}</td>
<td>{{c.location}}</td>
<td>{{c.code}}</td>
</tr>
I want to change the orderBy:'code' when column is clicked, assume that the user clicked on the column location, i want the orderBy condition to change to 'location' instead of code, and to be in this form
<tr ng-repeat="c in clients | orderBy:'location'">

angular.module('app', []).controller('ctrl', function($scope) {
$scope.prefix = '+';
$scope.sort = '';
$scope.sortFn = function(name) {
$scope.prefix = $scope.prefix == '-' ? '+' : '-';
$scope.sort = $scope.prefix + name;
}
$scope.arrow = function(name){
if($scope.sort.indexOf(name) != -1)
return $scope.prefix == '+' ? '↑' : '↓';
return '';
}
$scope.clients = [
{ name: 'Tom', age: 30 },
{ name: 'Max', age: 20 },
{ name: 'Sam', age: 40 },
{ name: 'Liza', age: 25 },
{ name: 'Henry', age: 35 }
]
})
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
th{
cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<table ng-app='app' ng-controller='ctrl'>
<thead>
<tr>
<th ng-click='sortFn("name")'>Name {{arrow("name")}}</th>
<th ng-click='sortFn("age")'>Age {{arrow("age")}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="c in clients | orderBy:sort">
<td>{{c.name}}</td>
<td>{{c.age}}</td>
</tr>
</tbody>
</table>

Use datatables.js for automate sorting
https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css
https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js

write ng-click on the column and call a function like setSortByParameter and set the field sortBy.
and now write the orderBy as below.
<tr ng-repeat="c in clients | orderBy:'{{sortBy}}'">

Related

Dynamic data-title with ng-repeat in AngularJS

I'm looking for a solution to show dynamic header in the angular table for some of its <td>
my data looks like
let data = [
{
id: 1,
name: 'name',
fields: {
field 1: { value: '123'},
field 2: {value: 'macx'}
}
},
{
id: 2,
name: 'name2',
fields: {
field 1: { value: '456'},
field 2: {value: '3333'}
}
}
]
it should show in one table, I mean fields attr's should show as extra columns in the same table
note: fields are dynamic and I can't know it exactly so I need to do something like this in code
if any idea how I can get that work or any other idea to get the view as explained
<tr ng-repeat="data in $data">
<td data-title="'id'|translate"
sortable="'id'">
{{data.id}}
</td>
<td ng-repeat="(key, value) in data.fields track by $index"
ng-show="columnsHash[key]"
data-title="customFieldsTitles[$index]"
filterable="{field:'fields', type:'text', align:'LEFT'}"
data-title-text="customFieldsTitles[$index]">
{{value && value.value || ''}}
</td>
<td ng-show="columnsHash.totalBenefitTarget"
data-title="'target_total_benefit' | translate"
sortable="'total_benefit_target'"
style="text-align:center;"
filterable="{field: 'total_benefit_target', type:'number_range', options: {min: Number.MIN_VALUE, max: Number.MAX_VALUE}}">
{{data.total_benefit_target | number: 0}}
</td>
<td ng-show="columnsHash.totalBenefitActual"
data-title="'actual_total_benefit' | translate"
sortable="'total_benefit_actual'"
style="text-align:center;"
filterable="{field: 'total_benefit_actual', type:'number_range',
options: {min: Number.MIN_VALUE, max: Number.MAX_VALUE}}">
{{data.total_benefit_actual | number: 0}}
</td>
<tr>
showing columns order is important so writing it like code above
thanks in advance
angular table use scope.$column to render tb cols so I solved that by using scope binding
<table ng-table="tableParams" ng-init="initTable()">
<td ng-repeat="(key, value) in data.fields"
data-title="'Custom Field'"
sortable="'fields'"
filterable="{field:'fields', type:'text', align:'LEFT'}">
{{value && value.value || ''}}
</td>
</table>
in controller
var tableColumns;
$scope.initTable = function(){
var scope = this;
$timeout(function(){
tableColumns = scope.$columns;
});
};
after loading data for table call this function to update columns title
function updateCustomFields(){
var columnTemplate, index;
var colCount = 0;
if (!tableColumns) {
return;
}
tableColumns.map(function(col, i){
if (col.title() === 'Custom Field'){
columnTemplate = col;
index = i;
tableColumns.splice(index, 1);
return true;
}
});
for(var fieldLabel in $scope.customFieldsHash){
(function (label) {
var column = angular.copy(columnTemplate);
column.id = column.id+colCount/10;
column.title = function(){ return label; };
tableColumns.splice(index+colCount, 0, column);
colCount++;
})(fieldLabel);
}
}

AngularJS: ng-repeat without similar key

I have list of objs:
[{
key:test1
name: name1
},
{
key:test1
name: name2
},
{
key:test2
name: name3
}]
And i use ng-repeat to display it:
<tr ng-repeat=item in list>
<td>{{item.key}}</td>
<td>{{item.name}}</td>
</tr>
Is it possible to combine values with similar keys without changing the structure? not to be displayed twice test1 in my case
now:
test1 : name1
test1 : name2
test2 : name3
desired result:
test1 : name1
_____ name2
test2 : name3
You can use groupBy filter:
angular.module('app', ['angular.filter']).controller('ctrl', function($scope){
$scope.list = [{
key:'test1',
name: 'name1'
}, {
key:'test1',
name: 'name2'
},{
key:'test1',
name: 'name3'
},{
key:'test2',
name: 'name4'
}];
})
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.16/angular-filter.js"></script>
<table ng-app='app' ng-controller='ctrl'>
<tbody>
<tr ng-repeat-start="(key, value) in list | groupBy: 'key'">
<td>{{key}}</td>
<td>{{value[0].name}}</td>
</tr>
<tr ng-repeat-end ng-repeat='item in value.splice(1)'>
<td></td>
<td>{{item.name}}</td>
</tr>
</tbody>
</table>
ng-repeat="item in list | unique:'key'"
Here is how you can achieve the common key value in a same place using angular-filter:
angular.module('app',['angular.filter']).controller('mainCtrl', function($scope){$scope.list = [{
key:'test1',
name: 'name1'
},
{
key:'test1',
name: 'name2'
},
{
key:'test2',
name: 'name3'
}]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.16/angular-filter.min.js"></script>
<div ng-app='app' ng-controller='mainCtrl'>
<div ng-repeat="(key, value) in list | groupBy: 'key'">
<span ng-repeat='val in value'>{{val.name}} </span>
</div>
</div>
Before using ng-repeat update the list.
function rd(o, k, v) {
var n = [];
var l = {};
for(var i in o) {
if (l.hasOwnProperty(o[i][k])){
o[i][v] = l[o[i][k]][v]+ " " + o[i][k]
l[o[i][k]] = o[i]
} else{
l[o[i][k]] = o[i];
}
}
for(i in l) {
n.push(l[i]);
}
return n;
}
var list = rd(arr, "key", "name");
You can try this:
var app = angular.module('myApp', ['angular.filter']);
app.controller('myCtrl', function($scope) {
$scope.items = [{
"key":"test1",
"name": "name1"
},
{
"key":"test1",
"name": "name2"
},
{
"key":"test2",
"name": "name3"
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.16/angular-filter.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="item in items | groupBy: 'key'">
<h3>Key : {{item[0].key}}</h3>
<p>Names : <span ng-repeat='i in item'>{{i.name}} </span></p>
</div>
</div>

Displaying json object details in knockout js

I have the following fiddle where I am trying to display the data in key:value pairs,
i.e., key as header and followed by the information as rows .
I have the data in this format:
self.data = ko.observableArray([{
1:
{
name: 'Name 1',
lastLogin: '8/5/2012'
}
}
, {
2:
{
name: 'Name 2',
lastLogin: '2/8/2013'
}
}
]);
I have fiddle as :
https://jsfiddle.net/1988/z7nnf0fh/1/
I am expecting as:
1
name Name 1 lastLogin 8/5/2012
2
name Name 2 lastLogin 2/8/2013
I'd personally move all logic to your viewmodel. Then you could either use ko.toJSON to stringify the contents of each object or if you really want to have the output like above, you could do:
function DataModel() {
var self = this;
self.data = ko.observableArray([{
1: {
name: 'Name 1',
lastLogin: '8/5/2012'
}
}, {
2: {
name: 'Name 2',
lastLogin: '2/8/2013'
}
}
]);
self.formattedValues = ko.observableArray([]);
self.formatData = function() {
var tempRow = [];
ko.utils.arrayForEach(self.data(), function(item) {
for (var i in item) {
for (var j in item[i]) {
tempRow.push({
key: j,
value: item[i][j]
});
}
self.formattedValues.push({
key: i,
rows: tempRow
});
tempRow = [];
}
})
};
self.formatData();
}
var dataModel = new DataModel();
ko.applyBindings(dataModel);
.name {
color: #bbb;
}
.value {
fot-weight: bold
}
th {
width: 25px;
}
p {
margin-right: 10px;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="template: { name: 'template', data: formattedValues }"></div>
<script type="text/html" id="template">
<table>
<tbody data-bind="foreach: $data">
<tr>
<td data-bind="text: key"></td>
</tr>
<tr>
<td data-bind="foreach: rows">
<p>
<span class="name" data-bind="text: key + ': '"></span>
<span class="value" data-bind="text: value"></span>
</p>
</td>
</tr>
</tbody>
</table>
</script>
Hope that helps in some way

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)
});
});

View not changing with click

In this fiddle :
http://jsfiddle.net/9fR23/187/
The table elements are not been hidden when I hit div element "Flip!". The elements should become hidden as I'm changing the state of the structure which is determined by ng-show
The map is being updated but does not seem to be applied ?
I tried adding $scope.$apply to block when flip is invoked but same result. How to update the state of ng-show when the underlying map data structure changes ?
fiddle code :
<div ng-app="myapp" ng-controller="FirstCtrl">
<table class="table table-striped">
<tr ng-repeat="person in people">
<td ng-show="errorMap([1])">{{ person.first + ' ' + person.last }}</td>
</tr>
</table>
<div ng-click="flipView()">Flip!</div>
</div>
var myapp = angular.module('myapp', []);
myapp.controller('FirstCtrl', function ($scope) {
var errorMap = new Object()
errorMap['1'] = 'true'
errorMap['2'] = 'false';
$scope.errorMap = errorMap
$scope.people = [
{ id: 1, first: 'John', last: 'Rambo' },
{ id: 2, first: 'Rocky', last: 'Balboa' },
{ id: 3, first: 'John', last: 'Kimble' },
{ id: 4, first: 'Ben', last: 'Richards' }
];
$scope.flipView = function(){
alert('flipped')
$scope.errorMap['1'] = 'false'
$scope.$apply
}
});
Update : I changed the json to contain values true , false instead of 'true , 'false'. But same result. Updated fiddle : http://jsfiddle.net/9fR23/188/
Updated code :
errorMap['1'] = true
errorMap['2'] = false;
I've edited your fiddle:
HTML
<div ng-app="myapp" ng-controller="FirstCtrl">
<table class="table table-striped">
<tr ng-repeat="person in people">
<td ng-show="errorMap">{{ person.first + ' ' + person.last }}</td>
</tr>
</table>
<div ng-click="flipView()">Flip!</div>
</div>
Javascript
var myapp = angular.module('myapp', []);
myapp.controller('FirstCtrl', function ($scope) {
$scope.errorMap=true;
$scope.people = [
{ id: 1, first: 'John', last: 'Rambo' },
{ id: 2, first: 'Rocky', last: 'Balboa' },
{ id: 3, first: 'John', last: 'Kimble' },
{ id: 4, first: 'Ben', last: 'Richards' }
];
$scope.flipView = function(){
alert('flipped');
$scope.errorMap = !$scope.errorMap; //this is actual flipping (show/hide)
}
});
Waiting for your feedback
It was just a little syntax erro. You have ( ) in errorMap([1]). Without this one, all is fine.
<td ng-show="errorMap[1]">{{ person.first + ' ' + person.last }} </td>
Moreover, I think a simple boolean could do the trick.
There is the forked Fiddle
In your view you are treating errorMap as a function but it is an object literal. Also you are passing an integer but the keys for the object are strings
Try
<td ng-show="errorMap['1']">{{ person.first + ' ' + person.last }}</td>
DEMO

Categories