How to make excel like cell in javascript or Angularjs dynamically? - javascript

I want to make excel like cell system but dynamically, Where i have to select every cell individually.
My desired output:
If i have 2 and 10, the output will be like that(above image). 2 means 2 row and 10 means 10 columns. the 2 and 10 is from database then javascript/angularjs should make the table according to those values. The second thing is that i have to select every individual cell using javascript. For example, i want to select B7 and if i click on that cell, an alert box will be shown with the selected cell number.
In real i want to store some values regarding that cell. How can i make every cell clickable? Any suggestion? I prefer angularjs.
Edit:
Acually i want to make Yard graphical view. Staff will select cell and input goods weight(in bootstrap modal). Then save. Next time if a cell/slot has weight before, it will be in different color(red-means the cell/slot is already filled with goods) and if he click on that cell , all details will be shown regarding to that cell like weight. Database table will store yard_id,cell_id,weiight. How can make query to get details from database to have my cell filled with color and show details if the cell has details before?
Edit 2:
You make an object in factory to set value in cell :
database[createKey({
row: 'A',
column: 1
})] = 12;
Here row A and column 1 is red colored by default. But in real app, i will have data for some cells like:
[{"row":"A","column":1,"weight":100},
{"row":"A","column":2,"weight":200}
].
Then how can i set those value on specific cells and have different bg color?
I want to use this method( loadData() ) to set color(like the one you set-red color) in the cell those have value stored in database when page load for the first time :
function loadData() {
fakeHttp.get('api/weights').then(function (result) {
$scope.weights = result.data;
console.log(result.data)
});
};
I will pass json data in result.data parameter(given above).

...in real app, i will have data for some cells like:... how can i set those value on specific cells and have different bg color?
You can keep loadData the same and change $scope.getWeight to accommodate the format of the data. This takes a dependency on lodash's find, since that makes things more concise. If you don't want to do that you can replace _.find with your own find method that does the same thing - I'll leave that as an exercise for you :)
http://plnkr.co/edit/b0q4qTyNjQp7J2IB7ayf?p=preview
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.0.1/lodash.js"></script>
JavaScript
$scope.getWeight = function (row, column) {
if ($scope.weights) {
// See if there's a record with the row and column.
var record = _.find($scope.weights, {
row: row,
column: column
});
// Was a record found with the row and column?
if (record) {
// If so return its weight.
return record.weight;
}
}
};
Staff will select cell and input goods weight(in bootstrap modal). Then save. Next time if a cell/slot has weight before, it will be in different color(red-means the cell/slot is already filled with goods) and if he click on that cell , all details will be shown regarding to that cell like weight...How can make query to get details from database to have my cell filled with color and show details if the cell has details before?
I didn't completely understand, but here's roughly what you could do for the parts I did understand. This assumes you have 3 endpoints - GET api/weights to get the weights; GET api/weight to get the weight for a single cell and POST api/weight to update a weight. You'll need to replace fakeHttp with $http and the actual url's. I don't know what Yard or Yard_id is.
http://plnkr.co/edit/aAiYbChTqmAwgky0WOJ3?p=preview
// TODO: Replace fakeHttp with $http
var module = angular.module('myApp', ['ui.bootstrap']);
module.controller('MainCtrl', function ($scope, $uibModal, fakeHttp) {
$scope.rows = [
'A',
'B'
];
$scope.columns = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
];
$scope.select = function (row, column) {
var modalInstance = $uibModal.open({
templateUrl: 'myModal.html',
controller: 'ModalInstanceCtrl',
resolve: {
row: function () {
return row;
},
column: function () {
return column;
}
}
});
modalInstance.result.then(loadData);
};
$scope.getWeight = function (row, column) {
if ($scope.weights) {
var key = createKey({
row: row,
column: column
});
return $scope.weights[key];
}
};
loadData();
function loadData() {
fakeHttp.get('api/weights').then(function (result) {
$scope.weights = result.data;
});
};
function createKey(data) {
var key = {
row: data.row,
column: data.column
};
return JSON.stringify(key);
}
});
module.controller('ModalInstanceCtrl', function ($scope, row, column, fakeHttp, $uibModalInstance) {
$scope.row = row;
$scope.column = column;
fakeHttp.get('api/weight', {
row: row,
column: column
}).then(function (result) {
$scope.weight = result.data;
});
$scope.save = function () {
fakeHttp.post('api/weight', {
row: row,
column: column,
weight: $scope.weight
}).then(function () {
$uibModalInstance.close();
});
};
});
module.factory('fakeHttp', function ($q) {
var fakeHttp = {};
var database = {};
database[createKey({
row: 'A',
column: 1
})] = 12;
fakeHttp.get = function (url, data) {
if (url === 'api/weight') {
var key = createKey(data);
return $q.when({ data:
database[key]
});
} else if (url === 'api/weights') {
return $q.when({ data:
database
});
} else {
alert('invalid url: ' + url);
}
};
fakeHttp.post = function (url, data) {
if (url === 'api/weight') {
var key = createKey(data);
database[key] = data.weight;
return $q.when({});
} else {
alert('invalid url: ' + url);
}
};
return fakeHttp;
function createKey(data) {
var key = {
row: data.row,
column: data.column
};
return JSON.stringify(key);
}
});
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<link data-require="bootstrap#3.3.7" data-semver="3.3.7" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<script data-require="angular.js#1.6.2" data-semver="1.6.2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.js"></script>
<script data-require="angular.js#1.6.2" data-semver="1.6.2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular-route.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.3.3/ui-bootstrap-tpls.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<table border="1" cellspacing="0">
<tbody>
<tr ng-repeat="row in rows">
<td ng-repeat="column in columns" style="width: 100px; cursor: pointer"
ng-style="{ background: getWeight(row, column) ? 'red' : '' }"
ng-click="select(row, column)">
{{row}}{{column}}
</td>
</tr>
</tbody>
</table>
</body>
</html>
myModal.html
<div class="modal-body">
Please enter weight for {{ row }}{{ column }}
<input type="text" class="form-control"
ng-model="weight" />
<button class="btn btn-primary"
ng-click="save()">Save</button>
</div>
How can i make every cell clickable?
Here's how to make every cell clickable in AngularJS.
http://plnkr.co/edit/XKa5WwjyYTugDZ744iWB?p=preview
Your question was very unclear. I couldn't tell what you wanted, exactly.
JavaScript:
module.controller('MainCtrl', function($scope) {
$scope.rows = [
'A',
'B'
];
$scope.columns = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
];
$scope.select = function(row, column) {
if ($scope.selectedRow === row && $scope.selectedColumn === column) {
$scope.selectedRow = undefined;
$scope.selectedColumn = undefined;
} else {
$scope.selectedRow = row;
$scope.selectedColumn = column;
}
};
});
HTML:
<body ng-controller="MainCtrl">
<table border="1" cellspacing="0">
<tbody>
<tr ng-repeat="row in rows">
<td ng-repeat="column in columns" style="width: 100px; cursor: pointer"
ng-click="select(row, column)"
ng-style="{ background: row == selectedRow && column == selectedColumn ? 'yellow' : 'none' }">
{{row}}{{column}}
</td>
</tr>
</tbody>
</table>
<br>
Selected (row, column):
<br>
({{selectedRow || 'undefined'}}, {{selectedColumn || 'undefined'}})
</body>

Related

How to splice all the items in AngularJS

I have a table and I'm using AngularJS to display it, there's a clear button where if clicked all the rows will be deleted from the table. I am using splice to do this but when I try to splice it, only the 1st and 3rd row get splice.
How do I splice all of the rows?
self.row.length = 3;
for (var index=0; index < self.row.length; index++) {
if (self.row[index].DDelDetailId != 0) {
self.deletedRow.push(angular.copy(self.row[index]));
}
console.log("index: "+index+" Rows: "+self.row.length)
self.row.splice(index, 1)
}
I already looked at all the similar questions but none of them helped me. It can splice if the self.row.length is 1 but if it is greater than 1 it leaves 1 row.
Below is what was printed in the console log:
Index: 0 Rows: 3
Index: 1 Rows: 2
I push all the deleted row to self.deletedRow then if user clicks save then the deleted rows will be deleted in the database. Each row has a delete button so user can delete all rows or delete 1 specific row.
As you're moving the index forward while deleting rows, you're skipping rows:
iteration 1:
index = 0
arr: [0, 1, 2]
arr.splice(0, 1) => arr: [1, 2] // deletes first item
iteration 2:
index = 1
arr: [1, 2]
arr.splice(1, 1) => arr: [1] // deletes second item
iteration 3:
index = 2
arr: [1]
arr.splice(2, 1) => arr [1] // tries to delete third item
If you delete the first item all the time, you won't skip anything:
arr.splice(0, 1)
It's also more efficient to remove all rows: arr = [] or arr.length = 0,
if clicked all the rows will be deleted from the table
Why you are using splice for every row you can clear that whole array. So use self.row=[] instead of using splice().
As per the comment below: I actually push all the deleted row to self.deletedRow then if user clicks save then the delete rows
assign the row values to self.deletedRow before delete your all rows.
self.deleteAll=function()
{
self.deletedRow = self.row;
self.row = [];
}
this Above way for all rows
and this below way for selected rows
self.deleteSingleRow = function(currentObject)// currentObject is `ng-repeat` directive object and you should be pass to the `deleteSingleRow` in html
{
self.deletedRow.push(currentObject);
//do your delete service call and rebind the `row` array
}
you can achieve this using splice itself
Here is the working example for whole requirement
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<link data-require="bootstrap#3.3.7" data-semver="3.3.7" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.21.0/moment.min.js"></script>
<script data-require="angular.js#1.6.6" data-semver="1.6.6" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<script>
(function() {
var app = angular.module("myApp", []);
app.controller('testCtrl', function($scope) {
var self = this;
self.data = [{"Product":"Body Spray","Location":"USA","Dec-2017":"234","Jan-18":"789","Feb-18":"234","Mar-18":"789","Apr-18":"234"},{"Product":"Groceries","Location":"USA","Dec-2017":"234","Jan-18":"789","Feb-18":"234","Mar-18":"789","Apr-18":"234"},{"Product":"Ready Cook","Location":"USA","Dec-2017":"234","Jan-18":"789","Feb-18":"234","Mar-18":"789","Apr-18":"234"},{"Product":"Vegetables","Location":"USA","Dec-2017":"234","Jan-18":"789","Feb-18":"234","Mar-18":"789","Apr-18":"234"}];
self.deletedData = [];
self.duplicateData = angular.copy(self.data);
self.clearData = function(element){
if(element){
var index = self.data.indexOf(element);
if(index > -1){
self.deletedData.push(angular.copy(element));
self.data.splice(index, 1);
}
}
else{
self.deletedData = angular.copy(self.data);
self.data.splice(0, self.data.length);
}
};
self.resetData = function(element){
//The table order wont change
self.data = angular.copy(self.duplicateData);
//The table order will change in this
/*angular.forEach(self.deletedData, function (item, index) {
self.data.push(item);
});*/
self.deletedData = [];
};
});
}());
</script>
</head>
<body ng-controller="testCtrl as ctrl">
<button ng-click="ctrl.clearData()">Delete All</button>
<button ng-click="ctrl.resetData()">Reset All</button>
<table class="table">
<thead>
<tr>
<th data-ng-repeat="(key, val) in ctrl.data[0] as header">
{{ key }}
</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="row in ctrl.data track by $index">
<td data-ng-repeat="(key, val) in ctrl.data[0]">
{{ row[key] }}
</td>
<td>
<button ng-click="ctrl.clearData(row)">Delete</button>
</td>
</tr>
</tbody>
</table>
</body>
</html>
It is because self.row.length is changing dynamically as you are splicing.
use a temp variable and store length of your array to delete all rows
e.g
var temp = self.row.length;
for(var index=0;index<temp;index++) {
//splice
}

checkbox filters not working as desired in AngularJS

I have a requirement to filter some properties using check boxes. Here what I wrote:
js code:
app.controller("filterCtrl", function ($scope, $http) {
$http({
method: 'GET',
url: contextPath + '/properties'
})
.then(function (response) {
var properties = response.data.properties;
var propertyFilters = response.data.filters;
$scope.properties = properties;
$scope.propertyFilters = propertyFilters;
$scope.usePropertyGroups = {};
$scope.usePropertyTypes = {};
$scope.usePropertyStates = {};
$scope.$watch(function () {
return {
properties: $scope.properties,
usePropertyGroups: $scope.usePropertyGroups,
usePropertyTypes: $scope.usePropertyTypes,
usePropertyStates: $scope.usePropertyStates
}
}, function (value) {
var filterType = [
{selected : $scope.usePropertyGroups, filterProp : 'propertyGroups'},
{selected : $scope.usePropertyTypes, filterProp : 'propertyTypes'},
{selected : $scope.usePropertyStates, filterProp : 'states'}
];
var filteredProps = $scope.propertyVOs;
for(var i in filterType){
filteredProps = filterData(filteredProps, filterType[i].selected, filterType[i].filterProp);
}
$scope.filteredProps = filteredVOs;
}, true);
});
})
var filterData = function(allData,selectedProps,equalData){
var afterFilter = [];
var selected = false;
for (var j in allData) {
var p = allData[j];
for (var i in selectedProps) {
if (selectedProps[i]) {
selected = true;
if (i == p[equalData]) {
afterFilter.push(p);
break;
}
}
}
}
if (!selected) {
afterFilter = allData;
}
return afterFilter;
};
html:
<div data-ng-controller="filterCtrl">
<div>
<table>
<thead>
<tr>
<th>property ID</th>
<th>property name</th>
<th>property description</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="vo in filteredProps">
<td>{{vo.id}}</td>
<td>{{vo.name}}</td>
<td>{{vo.description}}</td>
</tr>
</tbody>
</table>
</div>
<div>
<div class="filter-list-container">
<ul data-ng-repeat="(key,value) in propertyFilters.filterOfGroup">
<li><input type="checkbox" data-ng-model="usePropertyGroups[key]"/>{{key}}<span> ({{value}})</span></li>
</ul>
</div>
<div class="filter-list-container">
<ul data-ng-repeat="(key,value) in propertyFilters.filterOfType">
<li><input type="checkbox" data-ng-model="usePropertyTypes[key]"/>{{key}}<span> ({{value}})</span></li>
</ul>
</div>
<div class="filter-list-container">
<ul data-ng-repeat="(key,value) in propertyFilters.filterOfStates">
<li><input type="checkbox" data-ng-model="usePropertyStates[key]"/>{{key}}<span> ({{value}})</span></li>
</ul>
</div>
</div>
I defined three filters (property group, property type, and property state). so whenever user click the corresponding check box, table will show related properties. Everything looks good, the only issue is when I select the first check box (for example property group) table shows lets say 50 property of 100 total. If I click the next one it is filtering the 50 property which I already filtered instead of filtering the whole array (which is 100 properties). I mean I want to filter the whole properties whenever the user checks multiple check boxes. I have worked a lot on filterType loops in the controller to get it done but I couldn't. I really appreciate any help on this.
I noticed that this example is very similar to my case. if I check one filter from "Pant Size" and one filter from "Shirt Size" it would show just the matched items instead of all items.
i think its filter 1 time 50/100 item 2 time 20/50 remaining 50 witch already filter so you need on every check box click first bind grid then filter it.

Selecting a row in table based on content and clicking link from selected row - Protractor

I have a page object that looks like this:
<table border>
<th>Email</th>
<th>action</th>
<tr current-page="adminUsers.meta.page">
<td>admin#example.com</td>
<td>Delete permanently</td>
</tr>
<tr current-page="adminUsers.meta.page">
<td>matilda#snape.com</td>
<td>Delete permamently</td>
</tr>
</table>
I want to create a method that will enable me to delete a user based on his email address.
This is what I came up with, basing on How to find and click a table element by text using Protractor?:
describe('Admin panel', function() {
it('admin deletes a user', function() {
var re = new RegExp("matilda#snape.com");
var users_list = element.all(by.xpath("//tr[#current-page='adminUsers.meta.page']"));
var delete_btn = element(by.xpath("//a[contains(text(), 'Delete permamently')]"));
users_list.filter(function(user_row, index) {
return user_row.getText().then(function(text) {
return re.test(text);
});
}).then(function(users) {
users[0].delete_btn.click();
});
// some assertion, not relevant right now
});
});
First I'm trying to filter the row in which there's a user I want delete (array with all rows fitting my filter, then selecting the first row - should be one row anyway) and then click corresponding Delete button.
However, from my debugging I know that the method ignores the filtering and clicks the first Delete button available in the table and not the first from filtered elements.
What am I doing wrong?
In this particular case, I would use an XPath and its following-sibling axis:
function deleteUser(email) {
element(by.xpath("//td[. = '" + email + "']/following-sibling::td/a")).click();
}
I agree with #alexce's short & elegant answer but #anks, why don't you delete inside your filter??
describe('Admin panel', function() {
it('admin deletes a user', function() {
var re = new RegExp("matilda#snape.com");
var users_list = element.all(by.xpath("//tr[#current-page='adminUsers.meta.page']"));
var delete_btn = element(by.xpath("//a[contains(text(), 'Delete permamently')]"));
users_list.filter(function(user_row, index) {
return user_row.getText().then(function(text) {
return if(re.test(text)) { //assuming this checks the match with email id
user_row.delete_btn.click();
}
});
})
// some assertion, not relevant right now
});
});

bootstrap-table: how to nest one table into another?

I'm using this bootstrap-table. I'd like to nest one table into another.
$(document).ready(function() {
var t = [{
"id": "1",
"name": "john",
}, {
"id": "2",
"name": "ted"
}];
//TABLE 1
$('#summaryTable').bootstrapTable({
data: t,
detailFormatter: detailFormatter
});
function detailFormatter(index, row, element) {
$(element).html(row.name);
$(element).html(function() {
//I was thinking of putting the code here, but I don't know how to do it so it will work,
//except javascript, it needs to be put this html code <table id="detailTable"></table>
});
// return [
// ].join('');
}
//TABLE 2
var t2 = [{
"id": "1",
"shopping": "bike",
}, {
"id": "2",
"shopping": "car"
}];
$('#detailTable').bootstrapTable({
data: t2,
columns: [{
field: 'id',
title: 'id'
}, {
field: 'shopping',
title: 'Shopping detail'
}, {
field: 'status',
checkbox: true
}],
checkboxHeader: false
});
$('#detailTable').on('check.bs.table', function(e, row, $el) {
alert('check index: ' + row.shopping);
});
$('#detailTable').on('uncheck.bs.table', function(e, row, $el) {
alert('uncheck index: ' + row.shopping);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.0/bootstrap-table.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.0/bootstrap-table.min.js"></script>
<div class="container">
<p>TABLE 1</p>
<table id="summaryTable" data-detail-view="true">
<thead>
<tr>
<th data-field="id" data-align="center" data-width="20px">id</th>
<th data-field="name" data-align="center">Name</th>
</tr>
</thead>
</table>
<br>
<p>TABLE 2</p>
<table id="detailTable"></table>
</div>
Here is the link of my demo: fiddle
There are two tables. Table 1 has expandable rows and I want to put Table 2 into every row of table 1. There is this function called detailFormatter which does this and where you can return a string or render an element (I was playing with it, but I can't make it work). For this demo the table 1 is created with some html code and the table 2 uses only javascript, but there is this initiating div <table id="detailTable"></table> (it doesn't matter for me which way is done). So, the question is how to put the table 2 into table 1 with possibility of using its events (like check or uncheck checkbox) as the demo shows for table2? Later on, I'd like to use this event onExpandRow so when the user expands the row of table 1 it will get the data from a database and it'll fill out the table 2.
Well just clone your detailTable and put it in each row with detailFormatter as below:
function detailFormatter(index, row, element) {
$(element).html($('#detailTable').clone(true));
}
Now there will be duplicate id's created when you do clone, so you just remove it by changing its id as below:
function detailFormatter(index, row, element) {
$(element).html($('#detailTable').clone(true).attr('id',"tbl_"+row.id));
}
Also, you can hide the #detailTable since you are just having it to append it in another table and once you hide it you need to add show to cloned tables as all the properties will be copied to in clone(true) which can be done as below:
function detailFormatter(index, row, element) {
$(element).html($('#detailTable').clone(true).attr('id',"tbl_"+row.id).show());
}
//.....
//.....
//.....
//At the end
$("#detailTable").hide();
A complete DEMO
I found another way of nesting one table into another using (partly) dynamic table creation (referring to my posted question when using bootstrap-table).
var expandedRow = row.id;
$(element).html(
"<table id='detailTable"+expandedRow+"'><thead><tr><th data-field='id2' data-align='center' data-width='20px'>id2</th>" +
"<th data-field='shopping' data-align='center'>Shopping detail</th>" +
"<th data-field='status' data-checkbox='true'></th>" +
"</tr></thead></table>");
$('#detailTable'+expandedRow).bootstrapTable({
data: t2,
checkboxHeader: false
});
I think this way is more independent. There is no need to have one panel opened at the time. The events and methods seems to be working fine.
Full code here.

Creating and sorting table by column using underscore.js and knockout.js

First of all, i'm new to Knockout.js and underscore.js, and this is my first day of learning those libraries. The task is to sort table by clicking column header in ascending order on first click, and in descending order on second click.
I have this kind of HTML markup:
<table>
<thead>
<tr data-bind="foreach: columnNames">
<td data-bind="text: $data, click: $root.sortColumn, css: { 'active': $root.currentItem() == $data }"></td>
</tr>
</thead>
<tbody data-bind="foreach: persons">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: formattedAge"></td>
<td data-bind="text: sex"></td>
<td data-bind="text: married"></td>
</tr>
</tbody>
</table>
And this js code for knockout.js:
function personViewModel()
{
var self = this;
self.currentItem = ko.observable('');
self.columnNames = ko.observableArray([
'Name',
'Age',
'Sex',
'Married'
]);
self.persons = ko.observableArray([...]);
self.sortColumn = function(item)
{
self.currentItem(item);
var sorted = _(self.persons()).sortBy(item.toLowerCase());
self.persons(sorted);
};
};
ko.applyBindings(new personViewModel());
Now the question is:
Is it possible to get element descriptor, while one of td's clicked, so i could use something like '$(this)' in self.sortColumn?
Because now i can sort a table by clicking appropriate column header, but i don't know how to mark a column, that it already was clicked (and check it), to use _(self.persons()).sortBy(item.toLowerCase()).reverse(), to sort it in descending order of columns.
Thanks:)
Answer is simple. Right now you saving only column name, you need also have variable for sort direction, and your logic in sortColumn would be:
function personViewModel()
{
var self = this;
self.currentItem = ko.observable('');
self.sortDirection = ko.observable(true);
self.columnNames = ko.observableArray([
'Name','Age','Sex','Married'
]);
self.persons = ko.observableArray([
{ name : "John", formattedAge:27, sex:"Male", married:"No"},
{ name : "Bob", formattedAge:30, sex:"Male", married:"Yes"}
]);
self.sortColumn = function(item)
{
if (item == self.currentItem()) {
self.sortDirection(!self.sortDirection())
} else{
self.currentItem(item);
self.sortDirection(true)
}
if( self.sortDirection() ) {
var sorted = _(self.persons()).sortBy(item.toLowerCase());
self.persons(sorted);
} else {
var sorted = _(self.persons()).sortBy(item.toLowerCase()).reverse();
self.persons(sorted);
}
};
};
ko.applyBindings(new personViewModel());
See jsfiddle with working example.
Also notice that you don't really need underscore.js here, as ko.js provides you with
myObservableArray.reverse()
myObservableArray.sort()
Everything you need.
var sortDirection = true
self.sortColumn = function(item) {
if (item == self.currentItem()) {
sortDirection = !sortDirection
self.persons.reverse()
} else {
sortDirection = true
var field = self.currentItem()
self.persons.sort(function(left, right) {
return left[field] == right[field] ? 0
: ( left[field]< right[field] ? -1 : 1 )
})
}
}

Categories