Don't work sort in angular-tablesort - angularjs
I try to work with angular-sortable, but maybe I made something wrong because this code doesn't work.Where my mistake? All thead clickable, but it does sorting data in the table, just change css styles on click. Maybe I wrote wrong ts-criteria or wrong work with data?
My table:
<table ts-wrapper>
<thead>
<tr>
<th class="add">Add</th>
<th ts-criteria="population" ng-repeat="year in vm.years" ts-repeat>{{ year }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="city in vm.cities" ts-repeat>
<td >{{ city.name }}</td>
<td ng-repeat="population in city.population">{{ population }}</td>
</tr>
</tbody>
</table>
This is my controller:
(function () {
'use strict';
var app = angular.module("app",['tableSort']);
app.controller("TableController", TableController);
function TableController () {
var vm = this;
vm.years = ['2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014'];
vm.cities = [
{
"name":"Москва",
'population':{
'2005': '7000000',
'2006':'7300000',
'2007':'7800000',
'2008':'8000000',
'2009':'8400000',
'2010':'8700000',
'2011':'9000000',
'2012':'9400000',
'2013':'9800000',
'2014':'10000000'
}
},
{
"name":"Санкт-Петербург",
'population':{
'2005':'6000000',
'2006':'6300000',
'2007':'6800000',
'2008':'7000000',
'2009':'7400000',
'2010':'7700000',
'2011':'8000000',
'2012':'8400000',
'2013':'8800000',
'2014':'9000000'
}
},
{
"name":"Калининград",
'population':{
'2005':'2000000',
'2006':'2300000',
'2007':'2800000',
'2008':'3000000',
'2009':'3400000',
'2010':'3700000',
'2011':'4000000',
'2012':'4400000',
'2013':'4800000',
'2014':'4900000'
}
},
{
"name":"Архангельск",
'population':{
'2005':'295000',
'2006':'300000',
'2007':'305000',
'2008':'308000',
'2009':'310000',
'2010':'315000',
'2011':'318000',
'2012':'324000',
'2013':'331000',
'2014':'341000'
}
},
{
"name":"Астрахань",
'population':{
'2005':'493000',
'2006':'497000',
'2007':'499000',
'2008':'502000',
'2009':'504000',
'2010':'507000',
'2011':'509000',
'2012':'513000',
'2013':'514000',
'2014':'520000'
}
},
{
"name":"Уфа",
'population':{
'2005':'1028000',
'2006':'1034000',
'2007':'1036000',
'2008':'1038000',
'2009':'1042000',
'2010':'1047000',
'2011':'1051000',
'2012':'1054000',
'2013':'1059000',
'2014':'1062000'
}
},
{
"name":"Белгород",
'population':{
'2005':'318000',
'2006':'321000',
'2007':'330000',
'2008':'333000',
'2009':'339000',
'2010':'342000',
'2011':'345000',
'2012':'350000',
'2013':'354000',
'2014':'356000'
}
},
{
"name":"Брянск",
'population':{
'2005':'381000',
'2006':'384000',
'2007':'390000',
'2008':'394000',
'2009':'397000',
'2010':'400000',
'2011':'402000',
'2012':'404000',
'2013':'413000',
'2014':'415000'
}
},
{
"name":"Улан-Удэ",
'population':{
'2005':'370000',
'2006':'372000',
'2007':'375000',
'2008':'379000',
'2009':'384000',
'2010':'391000',
'2011':'396000',
'2012':'397000',
'2013':'400000',
'2014':'404000'
}
},
{
"name":"Волгоград",
'population':{
'2005':'991000',
'2006':'995000',
'2007':'999000',
'2008':'1001000',
'2009':'1004000',
'2010':'1010000',
'2011':'1012000',
'2012':'1015000',
'2013':'1019000',
'2014':'1021000'
}
},
];
}
}());
[Answer updated to match your fiddle]
There are many many problems:
The worst is that the tablesorter does not handle criteria columns
with names that are numeric (such as a year). So they need to be
parseable only as strings. Like "y2010" for example.
The ts-criteria="population['year']" thing doesn't work. There is no such array.
It doesn't seem to like your "track by" directives.
It doesn't like ng-repeats in the data columns either, so I had to take out the population sub-object.
Also you are not specifying a filter for the ts-criteria, which will screw up your sorting since the population numbers will be sorted as Strings ("900" > "10000" for example....).
So basically tablesorter will only work if you follow the example code really close :-). Unless you start fixing those problems. There is a fiddle at http://jsfiddle.net/o15bLvb2/2/ which makes all of this work.
Your body becomes:
<body ng-app="app" ng-controller="TableController as vm">
<table cellpadding="10" cellspacing="10" ts-wrapper >
<thead>
<tr>
<th class="add" ts-criteria="add" ts-default>Add</th>
<th ts-criteria="y2005|parseInt">y2005</th>
<th ts-criteria="y2006|parseInt">y2006</th>
<th ts-criteria="y2007|parseInt">y2007</th>
<th ts-criteria="y2008|parseInt">y2008</th>
<th ts-criteria="y2009|parseInt">y2009</th>
<th ts-criteria="y2010|parseInt">y2010</th>
<th ts-criteria="y2011|parseInt">y2011</th>
<th ts-criteria="y2012|parseInt">y2012</th>
<th ts-criteria="y2013|parseInt">y2013</th>
<th ts-criteria="y2014|parseInt">y2014</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="city in vm.cities track by city.name" ts-repeat>
<td>{{ city.name }}</td>
<td>{{ city.y2005 }}</td>
<td>{{ city.y2006 }}</td>
<td>{{ city.y2007 }}</td>
<td>{{ city.y2008 }}</td>
<td>{{ city.y2009 }}</td>
<td>{{ city.y2010 }}</td>
<td>{{ city.y2011 }}</td>
<td>{{ city.y2012 }}</td>
<td>{{ city.y2013 }}</td>
<td>{{ city.y2014 }}</td>
</tr>
</tbody>
</table>
</body>
Related
Angular execute get service based on array returned by antoher get with ForkJoin
Problem: Trying to populate a table with information from 2 services: The first service returns a lista of fabric plans that contain an array with machine operations. The second service is a get that returns a specific operation by id, that is used to get the information about the operation. The problem is that the service can only receive one id. How can I populate the table with the operation information knowing that a fabric plan as one or more operations. The Fabric Plan Model export class Fabricplan{ Id: number; Description: string; operationsIds: Array<Number> = []; DateStart: Date; } The service responsible for the post request: getOperation(Id):Observable<Operation[]>{ return this.http.get<Operation[]>(`${this.operations}${Id}`, httpOptions); } The html table is the following: <table class="table table-hover"> <thead class="thead-dark"> <tr> <th scope="col">Number</th> <th scope="col">Description</th> <th scope="col">Operations</th> <th scope="col">DateStart</th> </tr> </thead> <tbody> <tr scope="row" id="table" *ngFor="let fabricplan of fabricplans let i = index" (click)="open(content, fabricplan.id)"> <td>{{ i+1 }}</td> <td>{{ fabricplan?.description }}</td> <td>{{ oper_desc[id] }}</td> <td>{{ fabricplan?.dateStart }}</td> </tr> </tbody> </table> In the fabricplan.component.ts file ngOnInit() { this.fabricplanservice.getfabricplans().subscribe(fabricplans => { this.fabricplans = fabricplans; const opers_desc$ = this.fabricplans.map( element => this.operationservice.getOperation(element).pipe( // map it to the value you want map((response) => { this.operation = response; return this.operation['description']; }), // replace 404 responses with the 'No fabric plan' // if not 404 throw the error again catchError((error) => { if(error.status === 404){ return this.empt; } else { throwError(error); } } ))); forkJoin(opers_desc$).subscribe((opers_desc) => this.oper_desc = opers_desc); }); this.operationservice.getOperations().subscribe(operation => { this.operations = operation; }); } }
How to collapse and hide in ng-repeat over table?
So I have a table where I need to show parent deals and on ng-show(clicking parent deal) I want to show child deals. <table class="table table-hover"> <thead class="thead-dark"> <tr> <th scope="col">Name</th> <th scope="col">No_Of_Orders</th> <th scope="col">Size</th> <th scope="col">Book_Size</th> <th scope="col">Remarks</th> <th scope="col">Price_Guidance</th> <th scope="col">CONTROL</th> <th scope="col">Status</th> <th scope="col">Current_Cut_Off</th> <th scope="col">Tenor</th> <th scope="col">Book</th> <th scope="col">ORDCOLUMN</th> <th scope="col">PKEY</th> <th scope="col">Save</th> </tr> </thead> <tbody> <tr ng-repeat="parentDeal in parentDeals track by $index" ng-click="childShow(parentDeal.PKEY)"> <td>{{parentDeal.Name}}</td> <td>{{parentDeal.No_Of_Orders}}</td> <td>{{parentDeal.Size}}</td> <td>{{parentDeal.Book_Size}}</td> <td>{{parentDeal.Remarks}}</td> <td>{{parentDeal.Price_Guidance}}</td> <td>{{parentDeal.CONTROL}}</td> <td>{{parentDeal.Status}}</td> <td>{{parentDeal.Current_Cut_Off}}</td> <td>{{parentDeal.Tenor}}</td> <td>{{parentDeal.Book}}</td> <td>{{parentDeal.ORDCOLUMN}}</td> <td>{{parentDeal.PKEY}}</td> <td>{{parentDeal.Save}}</td> <tr ng-repeat="childDeal in childDeals track by $index" ng-show = "childRowShow_{{childDeal.PKEY}}"> <td>{{childDeal.Name}}</td> <td>{{childDeal.No_Of_Orders}}</td> <td>{{childDeal.Size}}</td> <td>{{childDeal.Book_Size}}</td> <td>{{childDeal.Remarks}}</td> <td>{{childDeal.Price_Guidance}}</td> <td>{{childDeal.CONTROL}}</td> <td>{{childDeal.Status}}</td> <td>{{childDeal.Current_Cut_Off}}</td> <td>{{childDeal.Tenor}}</td> <td>{{childDeal.Book}}</td> <td>{{childDeal.ORDCOLUMN}}</td> <td>{{childDeal.PKEY}}</td> <td>{{childDeal.Save}}</td> </tr> </tr> </tbody> </table> This is the basic data:- $scope.allDeals = [ { "ORDCOLUMN":"2017-11-17T05:00:00.000000000Z", "CONTROL":"N", "PKEY":"UD0000000000720", "Name":"rajat10 10:19", "Tenor":"0Y", "Size":0, "Price_Guidance":"43%", "Remarks":"-", "Book_Size":20, "Status":"Open", "No_Of_Orders":2, "Current_Cut_Off":2.3, "Book":"Book#ReOffer", "Save":"Edit" }, { "ORDCOLUMN":"2017-11-17T05:00:00.000000000Z", "CONTROL":"Y", "PKEY":"UD0000000000720", "Name":"rajat10 10:19", "Tenor":"Multi ...", "Size":0, "Price_Guidance":"-", "Remarks":"-", "Book_Size":20, "Status":" Open", "No_Of_Orders":2, "Current_Cut_Off":2.3, "Book":"Book#ReOffer", "Save":"Edit" }, { "ORDCOLUMN":"2017-11-17T05:00:00.000000000Z", "CONTROL":"N", "PKEY":"UD0000000000720", "Name":"rajat10 10:19", "Tenor":"Perp", "Size":0, "Price_Guidance":"19%", "Remarks":"-", "Book_Size":0, "Status":"Open", "No_Of_Orders":2, "Current_Cut_Off":2.3, "Book":"Book#ReOffer", "Save":"Edit" } ....and so on ] So, this data can be grouped by PKEY and parent object has control - "Y", child object has control - "N". Note:- There can be objects where there is only parent deal with no child deals. In my app.js:- $scope.parentDeals = $scope.allDeals.filter(function (item,index) { return item.CONTROL == "Y"; }); $scope.childDeals = []; $scope.childShow = function (PKEY) { if($scope["childRowShow_"+PKEY]){ $scope["childRowShow_"+PKEY] = false; } else{ $scope.childDeals = $scope.allDeals.filter(function (item,index) { if(item.PKEY == PKEY && item.CONTROL == "N"){ return item; } }); $scope["childRowShow_"+PKEY] = true; } }; Here, I am making two arrays:- parentDeals and childDeals. Right now, I am applying ng-repeat on the separate row so, child deals are showing after all parent deals. Is there any way I can show them below the respective parent deals or can apply a different solution?
Yes, with ng-repeat-start and ng-repeat-end, we can explicitly specify the starting and ending for ng-repeat. So, instead of using the ng-repeat directive on one single DOM element, we can specify the ng-repeat-start and ng-repeat-end on any two DOM elements. For eg. <div ng-app="app"> <table ng-controller="TestController"> <tr ng-repeat-start="d in data"> <td><strong>{{d.name}}</strong></td> </tr> <tr ng-repeat-end> <td>{{ d.info }}</td> </tr> </table> </div> <script> var app = angular.module('app', []); app.controller('TestController', function ($scope) { $scope.data = [{ name: 'ABC', info: 'Bangalore' }, { name: 'XYZ', info: 'Mumbai' }]; }); </script>
Angular js table with dynamic columns and values
I have a data structure as follow; [ { "a1": 941, "b1": "abc", "c1": "aaa", "a2": 27103, "b2": "ttt", "c2": "zzz" }, { "a1": 456, "b1": "xxx", "c1": "yyy", "a2": 7632, "b2": "mmm", "c2": "nnn" } ] I use angular js table with dynamic column names which are different from keys in the structure. Since there are many of them, I do not want to write key names like; <table st-table="table_data_raw" style="" class="table table-striped forms-list-table"> <tr> <th ng-repeat="dateColumnName in dateColumnNames ">{{ dateColumnName }} </th> </tr> <tbody> <tr ng-repeat="row in data"> <td>{{row.a1 }}</td> <td>{{row.b1 }}</td> <td>{{row.a2 }}</td> <td>{{row.b2 }}</td> <td>{{row.c2 }}</td> </tr> </tbody> </table> How can I get table values dynamically without specifying their names in that structure from "data"?
Try using $index to refer to the ng-repeat item you wish to access (in your example it would be index 0 or 1). Here is code/fiddle (click items in the table to get their value dynamically): https://jsfiddle.net/AdamKMorris/ox89o7L0/ using $Index: <tr ng-repeat="row in data"> <td ng-click="chosenValueA1($index);">{{row.a1 }}</td> ... </tr> Then the angularJs: $scope.chosenValueA1 = function(i) { $scope.myValue = $scope.data[i].a1; } If you want to access a1,a2,b1,b2, etc. then you will need to nest ng-repeat and use $index for each to refer to the value.
Pass value to another controller in angularjs
I am new to AngularJS. I have a div assigned controller to controller1. In this div, I am showing EmployeeList with three links for View, Edit,Delete for each employee. I have another div assigned controller to controller2. By clicking the view link on any employee, I want to show full details in second div. Both divs are in same page. How do I do that? Below is what I tried. <div ng-controller="employeeController" style="border:solid black 3px;float:left;padding:5px"> <h3 style="color:#ff6a00">List Of Employees</h3> <table> <tr> <th hidden>ID</th> <th>First Name</th> <th>Last Name</th> <th>Full Name</th> <th>Actions</th> </tr> <tr ng-repeat="employee in employees"> <td hidden><strong>{{ employee.ID }}</strong></td> <td>{{ employee.FName }}</td> <td>{{ employee.LName }}</td> <td><strong>{{ employee.FName + ' ' + employee.LName }}</strong></td> <td> <a data-ng-click="GetEmployeeByID({{employee.ID}})" href="javascript:;">View</a> </td> </tr> </table> </div> <div ng-controller="employeeByIDController" style="border:solid black 3px;float:right;padding:5px"> <h3 style="color:#ff6a00">Employee Details</h3> <table> <tr> <th hidden>ID</th> <th>Full Name</th> <th>Qualification</th> <th>Gender</th> <th>Phone</th> <th>Email</th> <th>Address</th> <th>City</th> </tr> <tr> <td hidden><strong>{{ employeeByID.ID }}</strong></td> <td>{{ employeeByID.FName + ' ' + employeeByID.LName }}</td> <td>{{ employeeByID.Qualification }}</td> <td>{{ employeeByID.Gender }}</td> <td>{{ employeeByID.Phone }}</td> <td>{{ employeeByID.Email }}</td> <td>{{ employeeByID.Address }}</td> <td>{{ employeeByID.City }}</td> </tr> </table> </div> The code in factory is as below. mainApp.factory('EmployeeFactory', function ($http) { return { GetEmployeeList: function () { return $http({ method: 'GET', url: '/AngularEmployee/EmployeeList' }); } } return { GetEmployeeByID: function ($id) { return $http({ method: 'GET', url: '/AngularEmployee/EmployeeByID', params: { empID : id } }); } } }); I have added controller as follows. mainApp.controller("employeeController", ['$scope', 'EmployeeFactory', function ($scope, EmployeeFactory) { $scope.GetEmployeeList = function () { EmployeeFactory.GetEmployeeList().success(function (data) { $scope.employees = data; }).error(function (data) { $scope.error = "An Error has occured while Loading users! " + data.ExceptionMessage; }); };$scope.GetEmployeeList(); }]);
Angular has a pubsub mechanism for this. It's well documented. E.g.: https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/
if you want to share data between two controllers in angularJs , using a service or factory is a better option as service/factory in angularJs are injectable.But service/factory is a singleton object so be aware of the fact that same object of the service/factory will be shared by all the controllers. Taking your example , you can create another service : mainApp.service('sharedService',function(){ this.employee={}; this.getter=function(){ return this.employee; }; this.setter=function(emp){ this.employee=emp; }; }); Then you can share this service across your controllers to get or set employee. mainApp.controller("employeeController", ['$scope', 'EmployeeFactory', 'sharedService', function($scope, EmployeeFactory, sharedService) { $scope.GetEmployeeList = function() { EmployeeFactory.GetEmployeeList().success(function(data) { $scope.employees = data; sharedService.setter($scope.employees);//set in shared service }).error(function(data) { $scope.error = "An Error has occured while Loading users! " + data.ExceptionMessage; }); }; $scope.GetEmployeeList(); }]); And then in employeeByIDControlle , mainApp.controller("employeeByIDController", ['$scope', 'EmployeeFactory', 'sharedService', function($scope, EmployeeFactory, sharedService) { $scope.employees = sharedService.getter();//get from shared service }]);
Dynamically setting new ng-model when pushing model to array
Can't figure out how to dynamically add a new model whenever a new row is added to the page. For example, the input select box ng-model= infos.rigBonusInfo.rigName is used for all select box I've added to the page. I would like to have a different model attached to a each select inputs. I tried using ng-model= infos.rigBonusInfo.rigName[rigBonus] but it doesn't work for the rates as the same model gets attachedto each rate field. Pretty much what I want to do is to bind a new model whenever a new row gets pushed into the array. Currently, I have a nested table which is the following: <div class="col-lg-5"> <table class="table table-striped table-bordered"> <thead> <tr> <th>Rig</th> <th>Rig Name</th> </tr> </thead> <tbody> <tr ng-repeat="rig in rigs"> <td>{{ $index + 1 }}</td> <td>{{ rig.name }}</td> </tr> </tbody> </table> </div> <div class="col-lg-2"></div> <div class="col-lg-5"> <table class="table table-striped table-bordered"> <thead> <tr> <th>Bonus Name</th> <th>Rate</th> </tr> </thead> <tbody> <tr ng-repeat="bonus in create.rigBonusRates"> <td>{{ bonus.rateName }}</td> <td>{{ bonus.rate }}</td> </tr> </tbody> </table> </div> <table> <thead> <tr> <th>Date</th> </tr> </thead> <tbody> <tr ng-repeat="rigDate in rigDateList track by $index"> <td><input ui-date="datepickerOptions" ng-model="date" /></td> <td> <table> <thead> <tr> <th>Rig</th> <th>Rate1</th> <th></th> <th>Rate2</th> <th></th> <th>Rate3</th> <th></th> <th>Rate4</th> <th></th> <th>Comments</th> </tr> </thead> <tr ng-repeat="rigBonus in rigBonusList track by $index"> <td><select ng-options="rig as rigs.indexOf(rig) + 1 for rig in rigs" ng-model="infos.rigBonusInfo.rigName[rigBonus]" ></select></td> #for (var i = 1; i < 5; i++) { <td><select ng-options="rigBonus.rateName for rigBonus in create.rigBonusRates" ng-model="infos.rigBonusInfo.rate#(#i)"></select></td> <td><input type="text" ng-disabled="infos.rigBonusInfo.rate#(#i).rateName != 'Special' " ng-model=infos.rigBonusInfo.rate#(#i).rate /></td> } <td><input ng-model="info.rigBonusInfo.comments" /></td> </tr> </table> </td> </tr> </tbody> </table> <div> <button type="button" ng-click="add()">Add</button> <button type="button" ng-click="addDate()">Add Date</button> </div> My current controller has the following: angular.module('RigBonus').controller('rigCreateController', ['$scope', '$http', 'PayPeriodService', 'RigLegendService', function ($scope, $http, PayPeriodService, RigLegendService, RigBonusRateService) { $scope.rigs = RigLegendService.getRigLegend(); $scope.datepickerOptions = { orientation: 'top', startDate: PayPeriodService.getStartDate(), endDate: PayPeriodService.getEndDate() }; $http({ method: 'GET', url: '/Home/CreateData' }).success(function (data) { $scope.create = data; $scope.infos = { rigBonusInfo: { rigName: $scope.rigs[0], rate1: $scope.create.rigBonusRates[0], rate2: $scope.create.rigBonusRates[0], rate3: $scope.create.rigBonusRates[0], rate4: $scope.create.rigBonusRates[0], comment: "" } }; $scope.add = function () { $scope.rigBonusList.push(); }; $scope.addDate = function(){ $scope.rigDateList.push(""); }; }); $scope.rigBonusList = [$scope.rigBonusInfo]; $scope.rigDateList = []; $scope.submit = function () { $http.post('/Home/Create', {model: "testing"} ); }; }]);
I figured out my issue. My problem was that I was not sure how to generate a new object when a new row of controls are added. Think I should have put something on fiddleJS to help people visualize it better. As a static model was used ($scope.infos) as ng-model, the same model was used for two different controls which I don't want. I want all my controls to be unique. The fix was to create the object I had in mind which is the following: $scope.rigDateList = [{ date: "", rigBonusList: [{}] }]; So it is an array of objects where the object contains a date and another array of objects. When I want to push new objects to the inside array which I didn't know I could just create objects like this at the time. I was trying to figure out a way to dynamically create new models ng-model could by declaring them in the controller. I use the following function: $scope.rigDateList[$scope.rigListIndex].rigBonusList.push({ rigName: "", rate1: "", rate2: "", rate3: "", comments: "" }); I also didn't know that I could use elements inside the array from ng-repeat. In the following case, it is rigBonus that I could have used as a model instead of infos model. <tr ng-repeat="rigBonus in rigDate.rigBonusList track by $index"> <td><select ng-options="rig as rigs.indexOf(rig) + 1 for rig in rigs" ng-model="rigBonus.rigName"></select></td> and when I want to push to the outside array I use the following: $scope.rigDateList.push({ date: "", rigBonusList: [""] }); $scope.rigListIndex = $scope.rigListIndex + 1; I use an index to keep track of which object I'm in.
A more closest question and answer is that: Ng-repeat with dynamic ng-model on input not working please, take a look.