Nested ng-repeat in html table - javascript
I have a table with three different levels of data, when I call the child level of data using an ng-click the data is diplayed ok but when I call the grandson level the data is not displayed, the response of my WS is ok because I can see it loged in my console so I after some time I realized that I need to nest my ng-repeat's in order to display the data from the grandson level but I don get how to do it, I checked also the ng-repeat-start directive but dont know if it apply to my htlm structure, this is what I have on my view.
<table class="table table-bordered drilldown-table" id="fixTable" style="height: 505px">
<tbody ng-repeat="cat in (exportData.result.slice(0, exportData.result.length-2))" >
<tr class="parent">
<td ng-click="drillDownSubcategoriesCat(cat.merchMetrics.DEPT_NBR,cat.merchMetrics.CATG_GRP_NBR,cat.merchMetrics.DEPT_CATG_NBR)" drill-down>+</td>
<td style="text-align: left">{{cat.merchMetrics.DEPT_CATG_DESC}}</td>
<!--SALES-->
<td>{{cat.merchMetrics.SALES_AMOUNT_LW | number : 2}}</td>
<td>{{cat.merchMetrics.SALES_LW_CHG_LY}}%</td>
<td>{{cat.merchMetrics.SALES_L4W_CHG_LY}}%</td>
<td>{{cat.merchMetrics.SALES_L13W_CHG_LY}}%</td>
<td>{{cat.merchMetrics.SALES_L52W_CHG_LY}}%</td>
<td>{{cat.merchMetrics.SALES_LW_VS_L13W}}</td>
</tr>
<tr ng-repeat="subcat in drillDownSubcatCatList['D' + cat.merchMetrics.DEPT_NBR + 'CG' + cat.merchMetrics.CATG_GRP_NBR + 'C' + cat.merchMetrics.DEPT_CATG_NBR]" class="child" ng-if="!$last" style="background-color: #f3eee9">
<td ng-click="drillDownCategoryItemsCat(subcat.merchMetrics.DEPT_NBR, subcat.merchMetrics.CATG_GRP_NBR, subcat.merchMetrics.DEPT_CATG_NBR, subcat.merchMetrics.DEPT_SUBCATG_NBR)" drill-down>+</td>
<td style="text-align: left; padding-left: 25px">{{subcat.merchMetrics.DEPT_SUBCATG_DESC}}</td>
<!--SALES-->
<td>{{subcat.merchMetrics.SALES_AMOUNT_LW | number : 2}}</td>
<td>{{subcat.merchMetrics.SALES_LW_CHG_LY}}%</td>
<td>{{subcat.merchMetrics.SALES_L4W_CHG_LY}}%</td>
<td>{{subcat.merchMetrics.SALES_L13W_CHG_LY}}%</td>
<td>{{subcat.merchMetrics.SALES_L52W_CHG_LY}}%</td>
<td>{{subcat.merchMetrics.SALES_LW_VS_L13W}}</td>
</tr>
<tr ng-repeat="items in drillDownCategoryItemCatList[nbrSubcatItem]" class="grandson" ng-if="!$last" style="background-color: #f3eee9">
<td></td>
<td style="text-align: left; padding-left: 45px">{{items.merchMetrics.DEPT_SUBCATG_DESC}}}</td>
<!--SALES-->
<td>{{items.merchMetrics.SALES_AMOUNT_LW | number : 2}}</td>
<td>{{items.merchMetrics.SALES_LW_CHG_LY}}%</td>
<td>{{items.merchMetrics.SALES_L4W_CHG_LY}}%</td>
<td>{{items.merchMetrics.SALES_L13W_CHG_LY}}%</td>
<td>{{items.merchMetrics.SALES_L52W_CHG_LY}}%</td>
<td>{{items.merchMetrics.SALES_LW_VS_L13W}}</td>
</tr>
</tbody>
To generate the data from the child and grandson level I call to functions.
$scope.drillDownSubcatCatList = {};
$scope.subcatNbr = '';
$scope.drillDownSubcategoriesCat = function (dept,group,catg) {
$scope.nbr1 = [dept];
$scope.nbr2 = [group];
$scope.nbr3 = [catg];
$scope.nbrSubcat = 'D' + $scope.nbr1 + 'CG' + $scope.nbr2 + 'C' + $scope.nbr3;
$scope.nbrSubcat.toString();
$scope.subCategoryConst = ['Product Sales (Subcategory Rank)'];
$scope.drillDownRecords = "5";
console.log($scope.nbr1);
console.log($scope.nbr2);
console.log($scope.nbr3);
console.log("NBR: " + $scope.nbrSubcat);
if (!($scope.nbrSubcat in $scope.drillDownSubcatCatList)) {
$scope.loadViewCategories = false;
$scope.graphLoading = "loading";
searchFactory.search('merchandise',
{
timeStamp: $scope.dateTime,
timeFrameType: $scope.whenType,
custMembSelectionType: $scope.customerType,
locationSelectionType: $scope.locationType,
merchandiseSelectionType: "Category",
startYear: $scope.whenStartParentYear,
endYear: $scope.whenStartParentYear,
startUnit: $scope.whenStartValue,
endUnit: $scope.whenStartValue,
comparator: $scope.locationType.indexOf('(Comp)', $scope.locationType.length - '(Comp)'.length) !== -1,
locationSelections: $scope.locationSelected,
merchandiseSelections: [$scope.nbrSubcat],
custMembSelections: $scope.customerSelected,
metricSelections: $scope.subCategoryConst,
rankOrder: $scope.drillDownRecords
}).success(function (data) {
console.log("drillDownSubcategories OK");
$scope.loadViewCategories = true;
$scope.graphLoading = "white";
$scope.canvasContent = true;
$scope.exportDataCategoryDrillDown = data;
$scope.metricSelected = $scope.filters.baropt.displayName;
if (data.error) {
$scope.noData = "There are no results based on your selected dropdowns. Please change your selection.";
$scope.data = undefined;
$scope.hasError = true;
}
$scope.isExportDisabled = 'auto';
if (!$scope.drillDownSubcatCatList[$scope.nbrSubcat]) {
$scope.drillDownSubcatCatList[$scope.nbrSubcat] = $scope.exportDataCategoryDrillDown.result;
}
}).error(function (ret, status) {
console.log(ret, status);
if (status == 500 || status == 0) {
if (ret.error.indexOf("Filter criteria not found!") > -1 || ret.error.indexOf("Bad Selections!") > -1) {
$scope.errorMessage = "The combination of dropdowns you selected is invalid. Please select a different combination.";
} else {
$scope.errorMessage = "The database may be down. Please contact Data Cafe Development Team - Applications for help.";
}
} else if (status == 400) {
$scope.errorMessage = "There was a bad request sent to the database. Please contact Data Cafe Development Team - Applications for help.";
} else {
$scope.errorMessage = "There was an error while trying to process your request. Please contact Data Cafe Development Team - Applications for help.";
}
$scope.hasError = true;
$scope.graphLoading = "white";
$scope.canvasContent = true;
$scope.showCaptions = false;
}
);
}
if($scope.nbrSubcat in $scope.drillDownSubcatCatList) {
console.log("--------------- " + $scope.nbrSubcat);
console.log("RETURN DD SUBCATEGORY LIST: ", $scope.drillDownSubcatCatList);
}
}
And this is the second function:
$scope.drillDownCategoryItemCatList = {};
$scope.drillDownCategoryItemsCat = function (dept,group,catg,subcat) {
$scope.nbr1 = [dept];
$scope.nbr2 = [group];
$scope.nbr3 = [catg];
$scope.nbr4 = [subcat];
$scope.nbrSubcatItem = 'D' + $scope.nbr1 + 'CG' + $scope.nbr2 + 'C' + $scope.nbr3 + 'SC' + $scope.nbr4;
$scope.nbrSubcatItem.toString();
$scope.ItemsConst = ['Product Sales (Item Rank)'];
$scope.drillDownRecords = "5";
console.log($scope.nbr1);
console.log($scope.nbr2);
console.log($scope.nbr3);
console.log($scope.nbr4);
console.log("NBR: " + $scope.nbrSubcatItem);
if (!($scope.nbrSubcatItem in $scope.drillDownCategoryItemCatList)) {
$scope.loadViewCategories = false;
$scope.graphLoading = "loading";
searchFactory.search('merchandise',
{
timeStamp: $scope.dateTime,
timeFrameType: $scope.whenType,
custMembSelectionType: $scope.customerType,
locationSelectionType: $scope.locationType,
merchandiseSelectionType: "SubCategory",
startYear: $scope.whenStartParentYear,
endYear: $scope.whenStartParentYear,
startUnit: $scope.whenStartValue,
endUnit: $scope.whenStartValue,
comparator: $scope.locationType.indexOf('(Comp)', $scope.locationType.length - '(Comp)'.length) !== -1,
locationSelections: $scope.locationSelected,
merchandiseSelections: [$scope.nbrSubcatItem],
custMembSelections: $scope.customerSelected,
metricSelections: $scope.ItemsConst,
rankOrder: $scope.drillDownRecords
}).success(function (data) {
console.log("drillDownCategortyItems OK");
$scope.loadViewCategories = true;
$scope.graphLoading = "white";
$scope.canvasContent = true;
$scope.exportDataCategoryItemDrillDown = data;
$scope.metricSelected = $scope.filters.baropt.displayName;
if (data.error) {
$scope.noData = "There are no results based on your selected dropdowns. Please change your selection.";
$scope.data = undefined;
$scope.hasError = true;
}
$scope.isExportDisabled = 'auto';
if (!$scope.drillDownCategoryItemCatList[$scope.nbrSubcatItem]) {
$scope.drillDownCategoryItemCatList[$scope.nbrSubcatItem] = $scope.exportDataCategoryItemDrillDown.result;
}
}).error(function (ret, status) {
console.log(ret, status);
if (status == 500 || status == 0) {
if (ret.error.indexOf("Filter criteria not found!") > -1 || ret.error.indexOf("Bad Selections!") > -1) {
$scope.errorMessage = "The combination of dropdowns you selected is invalid. Please select a different combination.";
} else {
$scope.errorMessage = "The database may be down. Please contact Data Cafe Development Team - Applications for help.";
}
} else if (status == 400) {
$scope.errorMessage = "There was a bad request sent to the database. Please contact Data Cafe Development Team - Applications for help.";
} else {
$scope.errorMessage = "There was an error while trying to process your request. Please contact Data Cafe Development Team - Applications for help.";
}
$scope.hasError = true;
$scope.graphLoading = "white";
$scope.canvasContent = true;
$scope.showCaptions = false;
}
);
}
if($scope.nbrSubcatItem in $scope.drillDownCategoryItemCatList) {
console.log("LIST FROM CATEGORY TO ITEM LEVEL: ", $scope.drillDownCategoryItemCatList);
}
}
As I mentioned before, the parent and the child level are displayed ok, so any idea on how can I nest the ng-repeat's in order to allow my grandson level to be displayed?
There is something strange here that you require a single table in the UI, but the underlying model is of a triply nested object. ng-repeat is not meant to be nested at sibling DOM levels.
The way I would recommend implementing this is to use an angular filter that will wrap all of your data into a single array that you can call ng-repeat on.
Your controller has wayyyyy too much logic in it. And I think this is contributing to the difficulties. In general, the controller should be in charge of displaying data that is being provided by angular services. The angular services should provide the data in a way that is easy for the controllers to consume.
If you find yourself creating nested if statements, xhr requests, and error handling inside of the controller, then you are doing something wrong. All of this should be refactored to several services (each service should have a SINGLE responsibility). Then you should have one of the services provide data to the controller that is easy for it to consume.
This is a bit of a vague answer, and not really a simple one. I think that the problems you are having come from not fully understanding how Angular implements the MVC pattern.
Related
Vue.js ignored when a blade is included in another blade
I have created a product card view in Laravel. the card has a simple "accordion" ('Show Details') - closed by default - that is managed by Vue.js as well as a Vue.js quantity counter that changes the weight value in grams if you add products. It all functions very well on the card's view and it looks like this (closed): I have another view in which I query my DB for product names with Vue.js to display all products of the same name as a result. The problem is when the cards are displayed on that "parent" view, they all appear with the accordion open and the counter is not responsive. It looks like so: As you can see, the tailwindcss code is rendered without a problem but the Vue.js is being completely ignored (Although the parent view's Vue.js functions work perfectly) What am I doing wrong? What am I missing here? Why are the directives inside the included blade being ignored? Here is the Vue.js method that manages the (product cards) views integration onto the parent (product name search) view: setGearItem(gearItem) { this.gearItem = gearItem; this.modal = false; console.log(gearItem); document.getElementById("displaySearch").innerHTML = ""; axios.get('/send-name-get-ids/' + this.gearItem) .then((response) => { console.log(response.data); if (response.data.length === 0) { document.getElementById("displaySearch").innerHTML = `"<strong>${gearItem}</strong>" was not found in our database. You can add it manually:`; this.generalForm = true; return; } else { for (let i = 0; i < response.data.length; i++) { axios.get('/gearitem/' + response.data[i]) .then((response) => { console.log(response.data); document.getElementById("displaySearch").innerHTML += response.data; this.generalForm = false; }) .catch((error) => { document.getElementById("displaySearch").innerHTML = "No items to display"; console.log(error); }); } } }); },
The problem is in the .innerHTML method as Vue.js ignores anything added via this method even if it's an AJAX. The solution consists on changing the controller to return a JSON and not a blade view, then using the JSON to populate a Vue.js component to create the item's card. the setGearItem() method was changed like so: setGearItem(gearItem) { this.gearItem = gearItem; this.modal = false; console.log(gearItem); document.getElementById("displaySearch").innerHTML = ""; this.displayItemCard = false; axios.get('/send-name-get-ids/' + this.gearItem) .then((response) => { console.log(response.data); this.gearItemId = response.data[0]; if (response.data.length === 0) { document.getElementById("displaySearch").innerHTML = `<p class="text-gray-700 "> <strong class="capitalize">${gearItem}</strong> was not found on our database. <br>You're free to add it manually! </p>`; this.generalForm = true; return; } else { this.displayItemCard = true; } }); }, the displayItemCard just activates the card component on the view and displays the correct card according to the id.
Dynamic query to take input from user and do filtering from the database node.js
enter image description hereWhat I'm trying is fetching columns from the user to which the user entered, The Good thing is Columns are getting fetched and the bad thing is the columns that I had applied conditions are not working.Can anyone help me out? I want a query that works for the filter option as in many websites to filter any product or something. Newbie here!!! routes.post('/FilterCandidate',function(req,res){ var fetchparameter={}; var dynamicquery={author : req.user.username}; if(req.user.username){ if(req.body.ConsultantName){ fetchparameter["ConsultantName"] = req.body.ConsultantName; } if(req.body.Location){ fetchparameter["Location"] = req.body.Location; } if(req.body.JobRole){ fetchparameter["JobRole"] = req.body.JobRole; } if(req.body.Skills){ fetchparameter["Skills"] = req.body.Skills.split(','); } if(req.body.VisaStatus){ fetchparameter["VisaStatus"] = req.body.VisaStatus; } if(req.body.BillingRate){ fetchparameter["BillingRate"] = req.body.BillingRate; } if(req.body.experience){ fetchparameter["experience"] = req.body.experience; } if(req.body.jobtype){ fetchparameter["jobtype"] = req.body.jobtype; } if(req.body.Availability){ fetchparameter["Availability"] = req.body.Availability; } if(req.body.experience){ fetchparameter["Salary"] = req.body.Salary; } if(req.body.Salarytype){ fetchparameter["Salarytype"] = req.body.Salarytype; } } /* This below code for conditions is not working*/ for(var key in fetchparameter){ if (key== "Salary" ){ dynamicquery[key] = {$gte :fetchparameter[key]}; } if(key == "Skills"){ dynamicquery [key] = {$in : fetchparameter[key]}; } if(key == "experience"){ dynamicquery[key] = {$gte :fetchparameter[key]}; } else{ dynamicquery[key] = fetchparameter[key]; } } console.log(dynamicquery); Candidate.aggregate([ {$match : dynamicquery }],(err,docs) =>{ res.render('FilteredCandidate',{'Candidates' : docs}); }); }); This is what I'm getting output to refer to the attached image
i think you should make a match object array it will make your code more neat and hoping that it will solve your problem Ex: var match = {$and:[]}; if(any condition satisfy){ match.$and.push({}) //condition } and most important do check if match.$and array must not be empty if it is then delete match.$and. this procedure will help you to maintain your query better provides more flexibility.
I can print the value in console but not in html view
I am new to angular js. I am trying to show data in dropdown but output is coming on console but not on html view. html:- <select ng-model="billing.billing" ng-options="billing in billAddress track by $index"> </select> <p>{{billing.billing}}</p> js file: appServices.getBillAddress(userData.customerId).then(function (data){ if (data){ console.log(data); $scope.addressToBill = data; var billAddress=[]; //var billAddress=[]; if ($scope.addressToBill){ storeLocally.set('shipInfo', $scope.addressToBill); for(var i=0;i<data.length;i++){ $scope.city = $scope.addressToBill[i].city; $scope.state = $scope.addressToBill[i].state; $scope.country = $scope.addressToBill[i].country; $scope.billAddress = $scope.city +", "+ $scope.state +", "+ $scope.country; console.log("billing address test: " +$scope.billAddress); } } } } }, function (data) { if (data.status == 500) { $scope.addressError = "Oops! No Address Found!"; }; }); data has information: [{city="fremont", country="USA", state="California"}] I am getting error in console: billing address test: fremont, California, USA Error: [ngOptions:iexp] Expected expression in form of 'select (as label)? for (key,)?value in collection' but got 'billing in billAddress track by $index'. I don't understand how to solve that select and ng-option error. If values are coming on console then Why it's not displaying in html dropdown. Please help me out.
First, your $scope.billAddress should be a collection, not a single string. Refactor your code as follows: .then(function(data){ if (!data) { // handling this case may vary; here I just clear the collection $scope.billAddress = []; return; } storeLocally.set('shipInfo', data); $scope.billAddress = data.map(function(address) { return { billing: address.city + ', ' + address.state + ', ' + address.country }; }); }); Second, you need to fix your ng-options syntax. One possible way: <select ng-model="selectedBilling" ng-options="billing.billing for billing in billAddress track by $index"> <p ng-bind="selectedBilling.billing"></p>
It looks like you always set it to the last one in the list. Not sure if that is on purpose.. if so let me know. But it sounds like you want to set billing address on each item and then use that as the label? If so set in your for loop data.billAddress = ... and use the below select. <select ng-model="selectedBilling" ng-options="billing as billing.billingAddress for billing in billAddress track by $index"> <p>{{selectedBilling}}</p>
This line won't work: <p>{{billing.billing}}</p> Cos the p is out of range from scope of select-> options just an snippet to illustrate! https://jsfiddle.net/alvarojoao/7wwdyymz/
AngularJS Select Box with 2000 options slow in IE
I understand that 2000 options in a select box is going to bring along some performance issues, but it works fine on Chrome and Firefox and Safari. Basically, I am calling a web service which populates a select box. This is fairly quick and performance is fine on initial load. The issue is when I change routes, and then come back to the page with the select box on it. It takes ~40 seconds to load the view on IE. Is there anyway way to improve performance? This is how it is set up: <select name="" id="" ng-model="model.searchParams.shipto" ng-options="ship.cd as ship.cd + (ship.cd===''?'' : ' - ') + ship.ds for ship in shiptoSelect" class="dropdownbar"></select> This is the call that is made to retrieve the results. This is only executed once, and then the results are stored in my globalParams. So when I return to this view, this is not executed and the results are loaded from my globalParams service. That is when I run into performance issues. $scope.getShipTo = function() { $scope.model.searchParams.shipto = ''; $scope.model.showProgress = true; MagicAPI.getShipToResults($scope.model.searchParams.brand, $scope.model.searchParams.soldto).then(function(response) { if (response.status === 200) { var resSHIPAR = eval(response.data); var resSHIPStr = resSHIPAR; if (resSHIPStr.length * 1 === 0) { globalParams.getAlertList().push({ type: 'info', msg: 'No ship-to\'s exist for this account.' }); $scope.model.showProgress = false; return; } else { var selectObj = { cd: '', ds: '-- select --' }; resSHIPStr.splice(0, 0, selectObj); globalParams.setShipToList(resSHIPStr); $scope.shiptoSelect = resSHIPStr; $scope.model.showProgress = false; for (var i = 0; i < resSHIPStr.length; i++) { if(resSHIPStr[i].cd === $scope.model.searchParams.soldto) { $scope.isSoldToMatch = true; return; } else { $scope.isSoldToMatch = false; } } if ($scope.isSoldToMatch === false) { globalParams.getAlertList().push({ type: 'info', msg: 'No ship-to\'s exist for this account.' }); } } } }, function(response) { $log.debug(response); }); };
You should really read about track by and implement it https://docs.angularjs.org/api/ng/directive/ngOptions then your select becomes <select name="" id="" ng-model="model.searchParams.shipto" ng-options="ship.cd as ship.cd + (ship.cd===''?'' : ' - ') + ship.ds for ship in shiptoSelect track by ship.id" class="dropdownbar"></select>
sorting dynamically created table from html form elemets
sorry for my english. I am new at this so i would appreciate a little help here, I have a html form and its data is shown on my page in html table. After each new saving form data table sorts by form entry id. Now i am stuck with sorting and pagination How can i sort this table data by clicking on column header for some other data, for example by animal_id or animal_name. Thanks for your help here is the code: init: function() { if (!Animals.index) { window.localStorage.setItem("Animals:index", Animals.index = 1); } Animals.$form.reset(); Animals.$button_discard.addEventListener("click", function(event) { Animals.$form.reset(); Animals.$form.id_entry.value = 0; }, true); Animals.$form.addEventListener("submit", function(event) { var entry = { id: parseInt(this.id_entry.value), animal_id:this.animal_id.value, animal_name: this.animal_name.value, animal_type: this.animal_type.value, bday: this.bday.value, animal_sex: this.animal_sex.value, mother_name: this.mother_name.value, farm_name: this.farm_name.value, money: this.money.value, weight: this.weight.value, purchase_partner: this.purchase_partner.value, }; if (entry.id == 0) { // add Animals.storeAdd(entry); Animals.tableAdd(entry); } else { // edit Animals.storeEdit(entry); Animals.tableEdit(entry); } this.reset(); this.id_entry.value = 0; event.preventDefault(); }, true); if (window.localStorage.length - 1) { var animals_list = [], i, key; for (i = 0; i < window.localStorage.length; i++) { key = window.localStorage.key(i); if (/Animals:\d+/.test(key)) { animals_list.push(JSON.parse(window.localStorage.getItem(key))); } } if (animals_list.length) { animals_list.sort(function(a, b) {return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); }) .forEach(Animals.tableAdd); } } Animals.$table.addEventListener("click", function(event) { var op = event.target.getAttribute("data-op"); if (/edit|remove/.test(op)) { var entry = JSON.parse(window.localStorage.getItem("Animals:"+ event.target.getAttribute("data-id"))); if (op == "edit") { Animals.$form.id_entry.value = entry.id; Animals.$form.animal_id.value = entry.animal_id; Animals.$form.animal_name.value = entry.animal_name; Animals.$form.animal_type.value = entry.animal_type; Animals.$form.bday.value = entry.bday; Animals.$form.animal_sex.value = entry.animal_sex; Animals.$form.mother_name.value = entry.mother_name; Animals.$form.farm_name.value = entry.farm_name; Animals.$form.money.value = entry.money; Animals.$form.weight.value = entry.weight; Animals.$form.purchase_partner.value = entry.purchase_partner; } else if (op == "remove") { if (confirm('Are you sure you want to remove this animal from your list?' )) { Animals.storeRemove(entry); Animals.tableRemove(entry); } } event.preventDefault(); } }, true); }, storeAdd: function(entry) { entry.id = Animals.index; window.localStorage.setItem("Animals:index",++Animals.index); window.localStorage.setItem("Animals:"+entry.id,JSON.stringify(entry)); }, storeEdit: function(entry) { window.localStorage.setItem("Animals:"+entry.id,JSON.stringify(entry)); }, storeRemove: function(entry) { window.localStorage.removeItem("Animals:"+ entry.id); }, tableAdd: function(entry) { var $tr = document.createElement("tr"), $td, key; for (key in entry) { if (entry.hasOwnProperty(key)) { $td = document.createElement("td"); $td.appendChild(document.createTextNode(entry[key])); $tr.appendChild($td); } } $td = document.createElement("td"); $td.innerHTML = '<a data-op="edit" data-id="'+ entry.id+'">Edit</a> | <a data-op="remove" data-id="'+ entry.id +'">Remove</a>'; $tr.appendChild($td); $tr.setAttribute("id", "entry-"+ entry.id); Animals.$table.appendChild($tr); }, tableEdit: function(entry) { var $tr = document.getElementById("entry-"+ entry.id), $td, key; $tr.innerHTML = ""; for (key in entry) { if (entry.hasOwnProperty(key)) { $td = document.createElement("td"); $td.appendChild(document.createTextNode(entry[key])); $tr.appendChild($td); } } $td = document.createElement("td"); $td.innerHTML = '<a data-op="edit" data-id="'+ entry.id +'">Edit</a> | <a data-op="remove" data-id="'+ entry.id +'">Remove</a>'; $tr.appendChild($td); }, tableRemove: function(entry) { Animals.$table.removeChild(document.getElementById("entry-"+ entry.id)); } }; Animals.init();
Since your current approach is to have your code managing the Table HTML and the Animal data directly, it will need to be your code that does the sorting of the data and the rewrite of the table. That is, you will need to listen for click events on the column headers, and then sort your Animal data according to that particular column, and then redraw the table completely. Redrawing the table could simply entail looping through your tableRemove() and then tableAdd() functions for all Animals being displayed, although that might be a little slow. The sorting of the data by each column is a bit more of a mess for which I have a solution below. A better approach would be to allow a RIA (Rich Internet Application) Framework to handle the table information for you. Many of these frameworks (EXT-JS, YUI, etc) provide a Table control that will simplify your coding dramatically. You merely give it a reference to your data (formatted in a relevant format), and it will do the sorting and display for you. If you still want to create the HTML Table yourself, and are more interested in the sorting of the data, then I would suggest going with a Client-side Database solution such as SequelSphere. With SequelSphere, you could create a table to manage your Animal data, as follows: db.catalog.createTable({ tableName: "animals", columns: ["id_entry", "animal_id", "animal_name", "animal_type", "bday", "animal_sex", "mother_name", "farm_name", "money", "weight", "purchase_partner"], primaryKey: ["id_entry"] }); Then you can Insert/Update/Delete rows like this: db.catalog.getTable("animals").insertRow( [ entry.id, entry.animal_id, entry.animal_name, entry.animal_type, entry.bday, entry.animal_sex, entry.mother_name, entry.farm_name, entry.money, entry.weight, entry.purchase_partner ] ); Finally, you can get your data Sorted by whatever column the user clicked by merely changing the ORDER BY clause in the following select statement: var sql = "SELECT id_entry, animal_id, animal_name, animal_type, " + " bday, animal_sex, mother_name, farm_name, money, " + " weight, purchase_partner " + " FROM animals " + " ORDER BY animal_sex "; // why did I choose this column? var sortedEntries = db.query(sql); Oh yes: SequelSphere also stores the data in window.localStorage, so you wouldn't have to write that either. It also has full support for SQL and cursors, so managing the Pagination would be a bit easier as well. Hope this helps! john...