How can I make pagination for my dynamic table? - javascript

My table is created with dynamic OO javascript and now I have to make pagination for rows - something like 5 rows(users) on the page :-? Also I need to display the pagination numbers when there are more than 5 users ...
This is the pice of code that make the display of the table :
(function (window) {
function ListView(store) {
var me = this;
this.store = store;
this.defaultTemplate = '<tr data-id = "{{id}}">' +
'<td><button class = "edit btna" type="button"></button>' +
'<button class = "delete btna" type="button" ></button></td>' +
'<td class = "userCol">' + '{{username}}' + '</td>' +
'<td class = "levelCol">' + '{{level}}' + '</td>' +
'<td class = "regCol">' + "<img src='img/" + '{{regstatus}}' + "_registered.png'>" + '</td>' +
'<td class = "dateCol">' + '{{regdate}}' + '</td>' +
'</tr>';
$(this.store).on("storeLoad", function () {
var data = this.getUsers();
me.show(data);
});
}
ListView.prototype.show = function (data) {
var i, l;
var view = '';
for (i = 0, l = data.length; i < l; i++) {
var template = this.defaultTemplate;
template = template.replace('{{id}}', data[i].id);
template = template.replace('{{username}}', data[i].username);
template = template.replace('{{level}}', data[i].level);
template = template.replace('{{regstatus}}', data[i].regstatus);
template = template.replace('{{regdate}}', data[i].regdate);
view = view + template;
}
console.log(data);
$('#userList').html(view);
};
// Export to window
window.app.ListView = ListView;
})(window);
Any ideeas ?

Related

How to optimize the DOM inserting loop

For example : I want to insert many tr in a table like this
var tbody = $('#tbody')
// Suppose the articlelist is the data from ajax
while (articlelist.length > 0) {
var article = articlelist.shift(),
var tr = $(' <tr>'
+' <td>'+article.id+'</td>'
+'<td>' + article.channelid +'</td>'
+ '<td>'+article.comment+'</td>'
+'<td>'+article.last_edit_time+'</td><td>'
)
tbody.append(tr)
}
To avoid create the <tr>...</tr> in loop .Is it possible to use a class to generate the tr content ?
An optimized version:
var tbody = $('#tbody'),
htmlStr = "";
for (var i = 0, len = articlelist.length; i < len; i++) { // avoid accessing 'length' property on each iteration
htmlStr += '<tr><td>' + articlelist[i].id + '</td>'
+ '<td>' + articlelist[i].channelid + '</td>'
+ '<td>' + articlelist[i].comment + '</td>'
+ '<td>' + articlelist[i].last_edit_time + '</td><td><tr>';
}
tbody.append(htmlStr); // parses the specified text as HTML or XML and inserts the resulting nodes
You could use a loop to concatenate all the strings, then append this lengthy string all at once. This would help with performance for many trs
var tbody = $('#tbody')
var rows = ''
while (articlelist.length > 0) {
var article = articlelist.shift(),
rows += '<tr><td>'+article.id+'</td>'
+'<td>' + article.channelid +'</td>'
+ '<td>'+article.comment+'</td>'
+'<td>'+article.last_edit_time+'</td><tr>';
}
tbody.append(rows)
add a function like this to do this for you.
while (articlelist.length > 0) {
make_content(article);
}
function make_content(article) {
var tbody = $('#tbody');
var tr = $(' <tr>'
+' <td>'+article.id+'</td>'
+'<td>' + article.channelid +'</td>'
+ '<td>'+article.comment+'</td>'
+'<td>'+article.last_edit_time+'</td><td>'
)
tbody.append(tr)
}

Looping through table returns undefined results

I have to make a dropdown of activities that a user can delete. The activities are held in a table which I'm trying to iterate over but I feel like I am almost there. I use Bootstrap 3 and jQuery. I'm still new to jQuery.
Here is the HTML I use to create a modal window, so I can put the control in there:
<div id="delete-activity-modal" class="modal fade" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h1>Delete Activity</h1>
</div>
<div class="modal-body">
<div class="input-group">
<span class="input-group-addon" id="add-addon-styling">Choose Activity</span>
<select class="form-control" id="delete-activity-modal-dropdown">
<!-- Options Added via content-controller.js -->
</select>
<span class="input-group-addon" data-toggle="tooltip" data-placement="top"
title="Choose the activity from the drop-down menu you want to delete.">
<b>?</b>
</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger btn-bg" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
As you see above, that's what I get out. I should have had 6 results and they should have an activity ID and a Name but they come back as undefined so I'm probably doing it wrong :P
Here is the function I use to make the dropdown content:
function CreateActivityDeleteDropdown() {
var dropdown = $('#delete-activity-modal-dropdown');
$('#activityTable').each(function() {
var activityId = $(this).attr("#activityId");
var activityName = $(this).attr("#activityName");
var dropdownDescription = activityId + " | " + activityName;
var dropdownElement = '<option value="' + activityId + '">' + dropdownDescription + '</option>';
$(dropdown).append(dropdownElement);
});
}
This function is only called when you press a button, so the table does exist when I do this. The table that I need to look through is dynamically added when the website loads like this:
function GetActivityAbstracts() {
$.getJSON(, function (testData) {
var object = $.parseJSON(testData);
var activityTable = '<tbody id="activityTable"></tbody>';
$.each(object, function () {
var activityId = this['ActivityId'];
var activityName = this['ActivityName'];
var activityResponsible = this['Responsible'];
var activityEstimatedSavings = parseFloat(this['EstimatedSavings']).toFixed(2);
var activityEstimatedStart = this['EstimatedStart'];
var activityEstimatedEnd = this['EstimatedEnd'];
var activityStatus = this['Status'];
// TODO: Make more user-friendly Status Descriptions instead of C# enum values.
var tableElement =
'<tr>' +
'<td id = "activityId" style = "vertical-align: middle; align: center;">'
+ activityId + '</td>' +
'<td style = "vertical-align: middle;">' +
'<div class="status-circle" data-toggle="tooltip" data-placement="right"' +
'title=" ' + activityStatus + '" style="background-color:' +
GetColumnColor(activityStatus) + ';"></div></td>' +
'<td id = "activityName" style = "vertical-align: middle;">'
+ activityName + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityResponsible + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityEstimatedSavings + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityEstimatedStart + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityEstimatedEnd + '</td>' +
'</tr>';
activityTable += tableElement;
});
$('#current-data-table').append(activityTable);
/* This call is necessary because the table is added dynamically */
$('[data-toggle="tooltip"').tooltip();
});
}
The result:
Some JSON Sample data:
"{\"1\":{\"ActivityId\":1,\"ActivityName\":\"Noget Med Penge\",\"Responsible\":\"Name\",\"EstimatedSavings\":9001.0,\"EstimatedStart\":\"19-11-2015\",\"EstimatedEnd\":\"01-01-2016\",\"Status\":\"NA\"},\"2\":{\"ActivityId\":2,\"ActivityName\":\"We need to shut down the bluetooth RAM hard drive!\",\"Responsible\":\"Name\",\"EstimatedSavings\":24589.0,\"EstimatedStart\":\"23-05-2014\",\"EstimatedEnd\":\"10-12-2015\",\"Status\":\"ON_TRACK\"},\"3\":{\"ActivityId\":3,\"ActivityName\":\"We need to encode the wireless RAM interface!\",\"Responsible\":\"Name\",\"EstimatedSavings\":874561.0,\"EstimatedStart\":\"11-04-1970\",\"EstimatedEnd\":\"22-01-2016\",\"Status\":\"DONE\"},\"4\":{\"ActivityId\":4,\"ActivityName\":\"We need to reboot the open-source PNG program!\",\"Responsible\":\"Name\",\"EstimatedSavings\":812654.0,\"EstimatedStart\":\"18-08-2000\",\"EstimatedEnd\":\"19-04-2016\",\"Status\":\"ISSUE\"},\"5\":{\"ActivityId\":5,\"ActivityName\":\"We need to program
the mobile CPU bus!\",\"Responsible\":\"Name\",\"EstimatedSavings\":-47998.0,\"EstimatedStart\":\"29-07-1982\",\"EstimatedEnd\":\"22-05-2016\",\"Status\":\"BEHIND\"},\"6\":{\"ActivityId\":6,\"ActivityName\":\"We need to network the optical GB port!\",\"Responsible\":\"Name\",\"EstimatedSavings\":74511.0,\"EstimatedStart\":\"23-10-1992\",\"EstimatedEnd\":\"27-09-2016\",\"Status\":\"ABANDONED\"}}"
First of all GetActivityAbstracts will create duplicate ids as I said. In the above code <td id = "activityId" and <td id = "activityName" inside $.each will be duplicate. Also use .find instead of .attr to find the elements inside each tr So you either change id to class or add index from .each to generate unique ids.
function GetActivityAbstracts() {
$.getJSON(, function (testData) {
var object = $.parseJSON(testData);
var activityTable = '<tbody id="activityTable"></tbody>';
$.each(object, function (index,value) {
//index here is used to generate unique ids
var activityId = this['ActivityId'];
var activityName = this['ActivityName'];
var activityResponsible = this['Responsible'];
var activityEstimatedSavings = parseFloat(this['EstimatedSavings']).toFixed(2);
var activityEstimatedStart = this['EstimatedStart'];
var activityEstimatedEnd = this['EstimatedEnd'];
var activityStatus = this['Status'];
// TODO: Make more user-friendly Status Descriptions instead of C# enum values.
var tableElement =
'<tr>' +
'<td id = "activityId_'+index+'" style = "vertical-align: middle; align: center;">'
+ activityId + '</td>' +
'<td style = "vertical-align: middle;">' +
'<div class="status-circle" data-toggle="tooltip" data-placement="right"' +
'title=" ' + activityStatus + '" style="background-color:' +
GetColumnColor(activityStatus) + ';"></div></td>' +
'<td id = "activityName_'+index+'" style = "vertical-align: middle;">'
+ activityName + '</td>' +
//Add index for ids here
'<td style = "vertical-align: middle;">'
+ activityResponsible + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityEstimatedSavings + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityEstimatedStart + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityEstimatedEnd + '</td>' +
'</tr>';
activityTable += tableElement;
});
$('#current-data-table').append(activityTable);
/* This call is necessary because the table is added dynamically */
$('[data-toggle="tooltip"').tooltip();
});
}
Now once you have this unique elements generated you can loop through each trs as below:
function CreateActivityDeleteDropdown() {
var dropdown = $('#delete-activity-modal-dropdown');
$('tbody#activityTable tr').each(function() {
var activityId = $(this).find("td [id^='activityId']").text();
//get value from the td whose id starts with activityId
var activityName = $(this).find("td [id^='activityName']").text();
//get value from the td whose id start with activityName
var dropdownDescription = activityId + " | " + activityName;
var dropdownElement = '<option value="' + activityId + '">' + dropdownDescription + '</option>';
$(dropdown).append(dropdownElement);
});
}
Now if you change td's id to class as below:
function GetActivityAbstracts() {
$.getJSON(, function (testData) {
var object = $.parseJSON(testData);
var activityTable = '<tbody id="activityTable"></tbody>';
$.each(object, function () {
var activityId = this['ActivityId'];
var activityName = this['ActivityName'];
var activityResponsible = this['Responsible'];
var activityEstimatedSavings = parseFloat(this['EstimatedSavings']).toFixed(2);
var activityEstimatedStart = this['EstimatedStart'];
var activityEstimatedEnd = this['EstimatedEnd'];
var activityStatus = this['Status'];
// TODO: Make more user-friendly Status Descriptions instead of C# enum values.
var tableElement =
'<tr>' +
'<td class = "activityId" style = "vertical-align: middle; align: center;">'
+ activityId + '</td>' +
'<td style = "vertical-align: middle;">' +
'<div class="status-circle" data-toggle="tooltip" data-placement="right"' +
'title=" ' + activityStatus + '" style="background-color:' +
GetColumnColor(activityStatus) + ';"></div></td>' +
'<td class= "activityName" style = "vertical-align: middle;">'
+ activityName + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityResponsible + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityEstimatedSavings + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityEstimatedStart + '</td>' +
'<td style = "vertical-align: middle;">'
+ activityEstimatedEnd + '</td>' +
'</tr>';
activityTable += tableElement;
});
$('#current-data-table').append(activityTable);
/* This call is necessary because the table is added dynamically */
$('[data-toggle="tooltip"').tooltip();
});
}
You can just use .find again to get respective td with its class as below:
function CreateActivityDeleteDropdown() {
var dropdown = $('#delete-activity-modal-dropdown');
$('#activityTable tr td').each(function() {
var activityId = $(this).find(".activityId").text();
var activityName = $(this).find(".activityName").text();
//getting using class
var dropdownDescription = activityId + " | " + activityName;
var dropdownElement = '<option value="' + activityId + '">' + dropdownDescription + '</option>';
$(dropdown).append(dropdownElement);
});
}
Update
Some more problems identified while creating DEMO
You were having var activityTable = '<tbody id="activityTable"></tbody>'; and then at the end, once you create a row you use to do activityTable += tableElement;. Since 'activityTablevariable already hadactivityTable +=used to append as...'which is why a newtbodywas getting created when appended toDOM. So either make ittbody` object by doing as below:
var activityTable = $('<tbody id="activityTable"></tbody>');
and then you can use .append to append the tr inside the created tbody as below:
$(activityTable).append(tableElement);
instead of activityTable += tableElement;
OR
If you prefer to keep your way then just append </tbody> once all the rows have been added as below:
var activityTable = '<tbody id="activityTable">'; //remove from here
and after $.each finishes you can just do
activityTable+="</table>";
Edit (example):
HTML:
<table>
<thead>
<th>
Activity ID
</th>
<th>
Status
</th>
<th>
Activity name
</th>
</thead>
<tbody id="activityTable">
</tbody>
</table>
<select>
</select>
JS:
$(document).ready(function(){
var JSONData = [[1,1,"name1"], [2,1,"name2"]];
var html = "";
var count = 0;
$.each(JSONData, function(){
html += "<tr>";
html += "<td data-type='id'>" + JSONData[count][0] + "</td>";
html += "<td data-type='status'>" + JSONData[count][1] + "</td>";
html += "<td data-type='name'>" + JSONData[count][2] + "</td>";
html += "</tr>";
count++;
});
var createOption;
$("#activityTable").html(html);
$("select").html("");
$("#activityTable tr").each(function(){
var data_id = $(this).find("td[data-type=id]").html();
var data_name = $(this).find("td[data-type=name]").html();
createOption = "<option>" + data_id + " | " + data_name;
$("select").append(createOption);
});
});
Output:
Demo: Click

Too many character literals in MVC View

Question Background:
I pass to my MVC view a ViewBag object which contain a list of items. These items are then added through the use of a For loop to a Javascript method called 'AddRows' which creates and adds a new HTML row to a table in the view.
The issue:
This code has worked before but I have run into an issue where I'm getting the following error:
The code:
#foreach (var cartItem in (List<LoginTest.Models.CartItem>)ViewBag.Data)
{
var cartItemId = '#cartItem.CartItemId';
var cartImage = '#cartItem.CartItemImage';
var cartItemName = '#cartItem.CartItemName';
var cartBrand = '#cartItem.CartItemBrand';
var cartItemPrice = '#cartItem.CartItemPrice';
var cartItemCartItemQty = '#cartItem.CartItemQty';
AddRows(cartItemId, cartImage, cartItemName, cartBrand, cartItemPrice, cartItemCartItemQty);
}
<script type="text/javascript">
var AddRows = function (productId, productImage, productName, productBrand, productPrice, productQty) {
var button = '<input class="btn btn-primary btn-block deleteItem" type="button" value="Remove"/>';
var image = '<img src="/Images/' + productImage + '" class="productCartImage"/>';
var selectors = '<input id="demo1" class="touchSpin" type="text" value="' + productQty + '" name="demo1">';
var $html = $('<tr class="item">' +
'<td class="prodId" style="display:none;">' + productId + '</td>' +
'<td class="prodImage hidden-xs">' + image + '</td>' +
'<td class="prodName">' + productName + '</td>' +
'<td class="prodBrand">' + productBrand + '</td>' +
'<td class="prodPrice"> £' + productPrice + '</td>' +
'<td class="prodQty TableCell">' + selectors + '</td>' +
'<td>' + button + '</td>' +
'</tr>');
$html.find("input[name='demo1']").TouchSpin({
min: 1,
max: 100,
step: 1,
});
$('#Table1 > tbody:last').append($html);
};
</script>
What I have tried so far:
Tried changing the single quote around each property of the item in the list from a single quote to a double. This will sort the string literal issue but then creates an error saying that the AddRows methed cannot be found.
Instead of
#foreach (var cartItem in (List<LoginTest.Models.CartItem>)ViewBag.Data)
{
var cartItemId = '#cartItem.CartItemId';
var cartImage = '#cartItem.CartItemImage';
var cartItemName = '#cartItem.CartItemName';
var cartBrand = '#cartItem.CartItemBrand';
var cartItemPrice = '#cartItem.CartItemPrice';
var cartItemCartItemQty = '#cartItem.CartItemQty';
AddRows(cartItemId, cartImage, cartItemName, cartBrand, cartItemPrice, cartItemCartItemQty);
}
Use this
#foreach (var cartItem in (List<LoginTest.Models.CartItem>)ViewBag.Data)
{
<text>
var cartItemId = '#cartItem.CartItemId';
var cartImage = '#cartItem.CartItemImage';
var cartItemName = '#cartItem.CartItemName';
var cartBrand = '#cartItem.CartItemBrand';
var cartItemPrice = '#cartItem.CartItemPrice';
var cartItemCartItemQty = '#cartItem.CartItemQty';
AddRows(cartItemId, cartImage, cartItemName, cartBrand, cartItemPrice, cartItemCartItemQty);
</text>
}
the <text> element tell Razor that the code shouldn't be considered as C#
Relocate this js variable declaration block inside script and force Razor interprite it as text with <text> tag. Like this:
<script type="text/javascript">
#foreach (var cartItem in (List<LoginTest.Models.CartItem>)ViewBag.Data)
{
<text>
var cartItemId = '#cartItem.CartItemId';
var cartImage = '#cartItem.CartItemImage';
var cartItemName = '#cartItem.CartItemName';
var cartBrand = '#cartItem.CartItemBrand';
var cartItemPrice = '#cartItem.CartItemPrice';
var cartItemCartItemQty = '#cartItem.CartItemQty';
AddRows(cartItemId, cartImage, cartItemName, cartBrand, cartItemPrice, cartItemCartItemQty);
</text>
}
var AddRows = function (productId, productImage, productName, productBrand, productPrice, productQty) {
var button = '<input class="btn btn-primary btn-block deleteItem" type="button" value="Remove"/>';
var image = '<img src="/Images/' + productImage + '" class="productCartImage"/>';
var selectors = '<input id="demo1" class="touchSpin" type="text" value="' + productQty + '" name="demo1">';
var $html = $('<tr class="item">' +
'<td class="prodId" style="display:none;">' + productId + '</td>' +
'<td class="prodImage hidden-xs">' + image + '</td>' +
'<td class="prodName">' + productName + '</td>' +
'<td class="prodBrand">' + productBrand + '</td>' +
'<td class="prodPrice"> £' + productPrice + '</td>' +
'<td class="prodQty TableCell">' + selectors + '</td>' +
'<td>' + button + '</td>' +
'</tr>');
$html.find("input[name='demo1']").TouchSpin({
min: 1,
max: 100,
step: 1,
});
$('#Table1 > tbody:last').append($html);
};
</script>

How do i find index of my object?

I have a table that is dynamicaly created something like this:
userData = Object Object Object...etc;
Object= username : ....
level:
regdate:
JavaScript code:
var buildTable = function () {
for (var i = 0, l = userData.length; i < l; i++) {
buildRow(userData[i]);
}
var buildRow = function (data) {
var html = '<tr><td>' + data.username + '</td>' +
'<td>' + data.level + '</td>' +
'<td>' + data.regstatus + '</td>' +
'<td>' + data.regdate + '</td>' +
'<td>' +
'<button value = "edit" id = "edit" onclick="tableOfUsers.editUser()">Edit</button>' +
'<button value= "delete" id = "delete" onclick="tableOfUsers.deleteUser()">Delete</button>' + '</td>';
$('#tableBody').append(html);
};
I have edtiUser/deleteUser function and i want when i click on edit/delete to edit/delete my row , my question is how do i find index of my object that i want to edite/delete without haveing an id field just with index of my objects?
Modify your code like this
for (var i = 0, l = userData.length; i < l; i++) {
buildRow(userData[i], i);
}
and
var buildRow = function (data, index) {
and
'<button value = "edit" id = "edit" onclick="tableOfUsers.editUser('+index+')">Edit</button>' +
'<button value= "delete" id = "delete" onclick="tableOfUsers.deleteUser('+index+')">Delete</button>' + '</td>';
$('#tableBody').append(html);
notice that we are passing index to the method being called from inside html strings.

Referencing an array item in a function (as string) javascript

I created an array of strings, with the format "monthX" where is a number that increases throughout the array.
I have a function where I'm trying to reference a specific item of the array, but it keeps coming in as undefined. Here's my code:
function listCategories() {
categoryList.innerHTML = ""
for (var propertyName in categoryObject) {
var rowHTML = "<div>"
rowHTML += "<span class = 'category'>" + categoryObject[propertyName].name + "</span>"
rowHTML += "<span class = '" + monthList[3] + "'><input/></span>"
rowHTML += "</div>"
categoryList.innerHTML += rowHTML
}
}
//Months to load in
for (var i=0; i<24; i++) {
monthList[i] = "month" + (i + startingMonth)
}
The area I'm interested in is that "monthList[3]" line. That keeps coming in as undefined, even though I console.log(monthList[3]) it correctly says "month6". Any ideas? Do I have bug in my code?
Well, two questions:
WHEN do you call "listCategories()" ?
before or after you set monthList?
And, have you set the global for monthList first?
//globalize monthList array to be usable in functions
var monthList;
function listCategories() {
categoryList.innerHTML = ""
for (var propertyName in categoryObject) {
var rowHTML = "<div>"
rowHTML += "<span class = 'category'>" + categoryObject[propertyName].name + "</span>"
rowHTML += "<span class = '" + monthList[3] + "'><input/></span>"
rowHTML += "</div>"
categoryList.innerHTML += rowHTML
}
}
//Months to load in
for (var i=0; i<24; i++) {
monthList[i] = "month" + (i + startingMonth)
}
//do NOT CALL listCategories prior this line!!
That should do
In the code you show us, you never declare monthList or define it as an array.
function listCategories() {
categoryList.innerHTML = ""
for (var propertyName in categoryObject) {
var rowHTML = "<div>"
rowHTML += "<span class = 'category'>" + categoryObject[propertyName].name + "</span>"
rowHTML += "<span class = '" + monthList[3] + "'><input/></span>"
rowHTML += "</div>"
categoryList.innerHTML += rowHTML
}
}
var monthList = [],
startingMonth = 1;
//Months to load in
for (var i=0; i<24; i++) {
monthList[i] = "month" + (i + startingMonth)
}
Notice the additional lines I added after the function definition, but before the loop.

Categories