append table data into table using loop - javascript

I want to append table data that I have saved in local storage. I have tried this loop to add in its cells and loop through changing the numbers based on the count or rows it reads. here is my JS code:
$(function() {
$("#loadTask").change(function() {
var task = loadTaskFromStorage1($("#loadTask").val());
var rows = $('#items-table tr').length;
var loop = 0;
var r = 1;
while (loop < rows) {
$("#items-table").append('<tr>'
+'<td>'+task.cells[r][0]+'</td>'
+'<td>'+task.cells[r][1]+'</td>'
+'<td>'+task.cells[r][2]+'</td>'
+'<td>'+task.cells[r][3]+'</tr>')
r += 1;
loop += 1;
}
})
})
this obviously does not work since im guessing when I JSON.Stringify the table data it saves it into one long string becuase when I added alert(row); before and after the loop I got 1 everytime even though the task had two rows.
Here is what I use to append the data into the table which I later save in local storage using a special name so I can save multiple different table datas :
function addRow() {
var item_text = $('#item-input').val();
var item_color = $('#color-input').val();
var size_text = $('#sizes-item').val();
var any_color = $('#any-color').is(':checked') ? 'Any Color' : '';
var any_size = $('#any-size').is(':checked') ? 'Any Size' : '';
$('#items-table').append('<tr>'
+'<td>'+item_text+', '+item_color+'</td>'
+'<td>'+size_text+'</td>'
+'<td>'+any_color+', '+any_size+'</td>'
+'<td><button class="remove-btn"><div class="thex">X</div></button><td>'
+'</tr>');
}
$(function(){
$('#add-item').click(function(){
addRow();
return false;
});
$('body').on('click', '.remove-btn', function(){
$(this).parent().parent().remove();
});
});
I thought that maybe since it wont count the table rows properly the only real thing that doesnt change at any table row is the remove button that gets added with every row.
So it tried changing
var rows = $('#items-table tr').length;
to:
var rows = $('#items-table button').length;
which I thought would work but when I added the alert part before and after the loop I got 0 every time.
What could I do to be able to count each row somehow to be able to append them properly back into the table the same way they were added in.
here is the javascript that saves the table data into localStorage:
$(function() {
loadAllTasks();
$("#addTask").click(function() {
let cells = Array.prototype.map.call($("#items-table")[0].rows, row => {
return Array.prototype.map.call(row.cells, cell => cell.innerHTML);
});
// create task object from cells
var task = {
cells: cells
};
var itemCount = $("#items-table tr").length - 1;
var lengthrows = {
itemCount: itemCount
}
saveLength(lengthrows);
var rowsCount = loadLength()
alert(rowsCount);
// set name property of the task
task.Name = $("#taskName").val();
// call save method using the new task object
saveTaskInStorage(task);
});
function saveTaskInStorage(task) {
// Get stored object from localStorage
var savedTasks = JSON.parse(localStorage.getItem('tasks'));
// To be sure that object exists on localStorage
if (!savedTasks || typeof(savedTasks) !== "object")
savedTasks = {};
// Set the new or exists task by the task name on savedTasks object
savedTasks[task.Name] = task;
// Stringify the savedTasks and store in localStorage
localStorage.setItem('tasks', JSON.stringify(savedTasks));
alert("Task has been Added");
}
function saveLength(lengthrows) {
var count = localStorage.getItem('lengthrows');
if (!count || typeof(count) !== "object")
savedCount = {};
savedCount[task.Name] = task;
localStorage.setItem('itemCount', savedTasks);
}
function loadLength(taskName) {
var lengthCount = localStorage.getItem("itemCount");
return lengthCount[taskName];
}
function loadAllTasks() {
// Get all saved tasks from storage and parse json string to javascript object
var savedTasks = JSON.parse(localStorage.getItem('tasks'));
// To be sure that object exists on localStorage
if (!savedTasks || typeof(savedTasks) !== "object")
return;
// Get all property name of savedTasks object (here it means task names)
for (var taskName in savedTasks) {
$("#loadTask").append('<option>' + taskName + '</option>')
}
}
});
function loadTaskFromStorage1(taskName) {
var savedTasks = JSON.parse(localStorage.getItem('tasks'));
//Return the task by its name (property name on savedTasks object)
return savedTasks[taskName];
}
I am also trying to save the count of the rows in each specific task. The stuff I attempted below with the saveLength doesn't work any suggestions?
Any help is appreciated Thank You <3

Your code when you need load task might be looks like that:
$(function() {
$("#loadTask").change(function() {
var task = loadTaskFromStorage1($("#loadTask").val());
var rows = task.cells;
let tpl = (rows) => {
return rows.slice(1).map(e => '<tr>' + e.map(e => `<td>${e}</td>`) + '</tr>');
}
$("#items-table").append(tpl(rows));
})
})
For removing tasks you need to add removeTask function which i've wrote:
function removeTask (taskName) {
var tasks = JSON.parse(localStorage.getItem('tasks'));
if (typeof tasks !== "object")
return false; // our tasks list not set. return negative.
delete tasks[taskName];
$('#loadTask > option:contains(' + taskName + ')').remove();
localStorage.setItem('tasks', JSON.stringify(tasks));
return true;
};
And modify your click listener at .remove-btn. Your listener should be look like that:
$('body').on('click', '.remove-btn', function(){
$(this).parent().parent().remove();
if ($('#items-table > tbody').children().length < 2) {
console.log("attemping to remove...");
if (removeTask($("#loadTask").val()))
alert('Task successfully removed.');
}
});

Related

JavaScript - Issues recovering a map in an object after being saved in localStorage

I've been dealing with this for some time. I've a list of sections in which the user checks some checkboxes and that is sent to the server via AJAX. However, since the user can return to previous sections, I'm using some objects of mine to store some things the user has done (if he/she already finished working in that section, which checkboxes checked, etc). I'm doing this to not overload the database and only send new requests to store information if the user effectively changes a previous checkbox, not if he just starts clicking "Save" randomly. I'm using objects to see the sections of the page, and storing the previous state of the checkboxes in a Map. Here's my "supervisor":
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
var children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children().length;
for (var i = 0; i < children; i++) {
if (i % 2 == 0) {
var checkbox = $("#ContentPlaceHolder1_checkboxes_div_" + id).children()[i];
var idCheck = checkbox.id.split("_")[2];
this.selections.set(idCheck, false);
}
}
console.log("Length " + this.selections.size);
this.change = false;
}
The console.log gives me the expected output, so I assume my Map is created and initialized correctly. Since the session of the user can expire before he finishes his work, or he can close his browser by accident, I'm storing this object using local storage, so I can change the page accordingly to what he has done should anything happen. Here are my functions:
function setObj(id, supervisor) {
localStorage.setItem(id, JSON.stringify(supervisor));
}
function getObj(key) {
var supervisor = JSON.parse(localStorage.getItem(key));
return supervisor;
}
So, I'm trying to add to the record whenever an user clicks in a checkbox. And this is where the problem happens. Here's the function:
function checkboxClicked(idCbx) {
var idSection = $("#ContentPlaceHolder1_hdnActualField").val();
var supervisor = getObj(idSection);
console.log(typeof (supervisor)); //Returns object, everythings fine
console.log(typeof (supervisor.change)); //Returns boolean
supervisor.change = true;
var idCheck = idCbx.split("_")[2]; //I just want a part of the name
console.log(typeof(supervisor.selections)); //Prints object
console.log("Length " + supervisor.selections.size); //Undefined!
supervisor.selections.set(idCheck, true); //Error! Note: The true is just for testing purposes
setObj(idSection, supervisor);
}
What am I doing wrong? Thanks!
Please look at this example, I removed the jquery id discovery for clarity. You'll need to adapt this to meet your needs but it should get you mostly there.
const mapToJSON = (map) => [...map];
const mapFromJSON = (json) => new Map(json);
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
this.change = false;
this.selections.set('blah', 'hello');
}
Supervisor.from = function (data) {
const id = data.id;
const supervisor = new Supervisor(id);
supervisor.verif = data.verif;
supervisor.selections = new Map(data.selections);
return supervisor;
};
Supervisor.prototype.toJSON = function() {
return {
id: this.id,
verif: this.verif,
selections: mapToJSON(this.selections)
}
}
const expected = new Supervisor(1);
console.log(expected);
const json = JSON.stringify(expected);
const actual = Supervisor.from(JSON.parse(json));
console.log(actual);
If you cant use the spread operation in 'mapToJSON' you could loop and push.
const mapToJSON = (map) => {
const result = [];
for (let entry of map.entries()) {
result.push(entry);
}
return result;
}
Really the only thing id change is have the constructor do less, just accept values, assign with minimal fiddling, and have a factory query the dom and populate the constructor with values. Maybe something like fromDOM() or something. This will make Supervisor more flexible and easier to test.
function Supervisor(options) {
this.id = options.id;
this.verif = null;
this.selections = options.selections || new Map();
this.change = false;
}
Supervisor.fromDOM = function(id) {
const selections = new Map();
const children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children();
for (var i = 0; i < children.length; i++) {
if (i % 2 == 0) {
var checkbox = children[i];
var idCheck = checkbox.id.split("_")[2];
selections.set(idCheck, false);
}
}
return new Supervisor({ id: id, selections: selections });
};
console.log(Supervisor.fromDOM(2));
You can keep going and have another method that tries to parse a Supervisor from localStorageand default to the dom based factory if the localStorage one returns null.

How to update JavaScript array dynamically

I have an empty javascript array(matrix) that I created to achieve refresh of divs. I created a function to dynamically put data in it. Then I created a function to update the Array (which I have issues).
The Data populated in the Array are data attributes that I put in a JSON file.
To better undertand, here are my data attributes which i put in json file:
var currentAge = $(this).data("age");
var currentDate = $(this).data("date");
var currentFullName = $(this).data("fullname");
var currentIDPerson = $(this).data("idPerson");
var currentGender = $(this).data("gender");
Creation of the array:
var arrayData = [];
Here is the function a created to initiate and addind element to the Array :
function initMatrix(p_currentIDPerson, p_currentGender, p_currentFullName, p_currentDate, p_currentAge) {
var isFound = false;
// search if the unique index match the ID of the HTML one
for (var i = 0; i < arrayData.length; i++) {
if(arrayData[i].idPerson== p_currentIDPerson) {
isFound = true;
}
}
// If it doesn't exist we add elements
if(isFound == false) {
var tempArray = [
{
currentIDPerson: p_currentIDPerson,
currentGender: p_currentGender,
currentFullName: p_currentFullName,
currentDate: p_currentDate, currentAge: p_currentAge
}
];
arrayData.push(tempArray);
}
}
The update function here is what I tried, but it doesn't work, maybe I'm not coding it the right way. If you can help please.
function updateMatrix(p_currentIDPerson, p_currentGender, p_currentFullName, p_currentDate, p_currentAge) {
for (var i = 0; i < arguments.length; i++) {
for (var key in arguments[i]) {
arrayData[i] = arguments[i][key];
}
}
}
To understand the '$this' and elm: elm is the clickableDivs where I put click event:
(function( $ ) {
// Plugin to manage clickable divs
$.fn.infoClickable = function() {
this.each(function() {
var elm = $( this );
//Call init function
initMatrixRefresh(elm.attr("idPerson"), elm.data("gender"), elm.data("fullname"), elm.data("date"), elm.data("age"));
//call function update
updateMatrix("idTest", "Alarme", "none", "10-02-17 08:20", 10);
// Définition de l'evenement click
elm.on("click", function(){});
});
}
$('.clickableDiv').infoClickable();
}( jQuery ));
Thank you in advance
Well... I would recommend you to use an object in which each key is a person id for keeping this list, instead of an array. This way you can write cleaner code that achieves the same results but with improved performance. For example:
var myDataCollection = {};
function initMatrix(p_currentIDPerson, p_currentGender, p_currentFullName, p_currentDate, p_currentAge) {
if (!myDataCollection[p_currentIDPerson]) {
myDataCollection[p_currentIDPerson] = {
currentIDPerson: p_currentIDPerson,
currentGender: p_currentGender,
currentFullName: p_currentFullName,
currentDate: p_currentDate,
currentAge: p_currentAge
};
}
}
function updateMatrix(p_currentIDPerson, p_currentGender, p_currentFullName, p_currentDate, p_currentAge) {
if (myDataCollection[p_currentIDPerson]) {
myDataCollection[p_currentIDPerson] = {
currentGender: p_currentGender,
currentFullName: p_currentFullName,
currentDate: p_currentDate,
currentAge: p_currentAge
};
}
}
Depending on your business logic, you can remove the if statements and keep only one function that adds the object when there is no object with the specified id and updates the object when there is one.
I think the shape of the resulting matrix is different than you think. Specifically, the matrix after init looks like [ [ {id, ...} ] ]. Your update function isn't looping enough. It seems like you are trying to create a data structure for storing and updating a list of users. I would recommend a flat list or an object indexed by userID since thats your lookup.
var userStorage = {}
// add/update users
userStorage[id] = {id:u_id};
// list of users
var users = Object.keys(users);

Access js array in another js file

I fill my array in the checklistRequest.js and I want to access it in my Termine_1s.html file which contains js code. I can access it but when I want to iterate through it, it gives me only single digits instead of the strings.
How can I solve this?
checklistRequest.js
//Calls the checkbox values
function alertFunction()
{
//Retrieve the object from storage
var retrievedObject = localStorage.getItem('checkboxArray');
console.log('retrievedObject: ', JSON.parse(retrievedObject));
return retrievedObject;
}
Termine_1s.html
//Checks if title was checked already
var checklistRequest = alertFunction();
var titleAccepted = true;
for (var a = 0; a < checklistRequest.length; a++)//Iterates through whole array
{
if(title != checklistRequest[i] && titleAccepted == true)//Stops if false
{
titleAccepted = true;
}
else
{
titleAccepted = false;
}
}
you need to parse the object at some point.
Try:
return JSON.parse(retrievedObject);

Show contents of localStorage into div

I have this basic function :
pid = 1;
$(function() {
if (localStorage["key"+pid] != null) {
var contentsOfDiv = localStorage.getItem("key"+pid);
$("#Div").html(contentsOfdDiv);
}
});
The problem is that the pid value will change eventually and I don't want to overwrite the contents of the key.
How can I proceed to stack every Div content that localStorage is saving for me ?
You can iterate on localStorage entries just like on any object properties :
for (var key in localStorage) {
console.log(key, localStorage[key]);
}
So your code could be :
$(function() {
var lines = [];
for (var key in localStorage) {
if (/^key/.test(key)) { // does the key start with "key"
lines.push(key.slice(3) + ' = ' + localStorage[key]);
}
}
$("#Div").html(lines.join('<br>'));
});
If I have understood well, you want to use pid to loop over the object.
Best way to do this and avoid for in chain prototypical problems is the following:
(I think for this case you are better with an array rather than with an object)
http://jsfiddle.net/hqkD9/
var localStorage = ['aaaa', 'bbbbb', 'cccc', 'dddd']; // don't forget to declare with var
var html_string = '';
$.each(localStorage, function(index, value) {
html_string += value + '<br>';
});
$('#my_div').html(html_string);

Excel Type Filter popup for Jqgrid

I need to have a filter ( like in Excel spread Sheet) to embedded to the 'jquery' dialog popup. in this case i need to show all the unique values in the column and check box just before that value to select to the user. when user pressed filter button i need to filter only the values that user requested through the check boxes.
Can any one please let me any approach that i must follow.
Thanks in advance for your help and valuable time.
I was able to develop basic grid with excel kind of filter feature. any one who will come across this type of requirement can use this answer as a foundation.
I use this answer from 'Oleg' to embed the filter popup screen to the basic 'jqgrid'.
in the jqgrid page declare this array with the attributes (columns) that needs to display the filter screen popup.
var applyFilterColumnNames = ['Id','Type','custId','UserId'];
and the column model should be as follows -
colModel :[
{name:'Id', index:'Id',hidden: true,sortable: true},
{name:'custId', index:'custId', width:140,align:"left",sortable: true,search : false},
{name:'Type', index:'Type', width:120,align:"left",sortable: true,search : false},
{name:'UserId', index:'UserId', width:150,align:"left",sortable: true,search : false},
],
used that reference answer to embed the filter button function.
gr.closest("div.ui-jqgrid-view").find("div.ui-jqgrid-hdiv table.ui-jqgrid-htable tr.ui-jqgrid-labels > th.ui-th-column > div.ui-jqgrid-sortable")
.each(function () {
var idPrefix = "jqgh_" + gr[0].id + "_";
var idIndex = (this.id).substr(idPrefix.length,this.id.length) ;
if(includeInArray(applyFilterColumnNames,idIndex)){
jq('<button id=btn_'+idIndex+'>').css({float: "right", height: "17px"}).appendTo(this).button({
icons: {
primary: "ui-icon-gear"
},
text: false
}).click(function (e) {
var idPrefix = "jqgh_" + gr[0].id + "_";
// thId will be like "jqgh_list_name"
var thId = jq(e.target).closest('div.ui-jqgrid-sortable')[0].id ;
if (thId.substr(0, idPrefix.length) === idPrefix) {
var colName = thId.substr(idPrefix.length);
//alert('Clicked the button in the column "' + colName + '"');
constructFilter(colName);
return false;
}
});
//}
}
});
Below is the script i used to filter the jqgrid according to the filters
//Variables that use in filtering operation
var originalData = null;
var filteredData;
var selectedFilters = new Object();
var chkBoxElement;
var firstSortColumn;
function constructFilter(columnName){
// for the first initiation of the filter populate current grid data to an array
if(originalData == null || originalData == 'null'){
try{
// this array will hold the initail data set of the grid
originalData = gr.jqGrid('getGridParam','data');
// set the first sorting grid column
firstSortColumn = columnName;
// check if column is associated with a formatter. if so format the originalData values accordingly.
formatGridData(columnName);
}catch(e){}
}
var colData = new Array();
var filterDataSet;
// if current column is equal to initial sorted column set all posible values to the check boxes in the
// filter screen to select. ( since this is the master sorting column and other columns will filter according to that)
if(columnName == firstSortColumn){
filterDataSet = originalData;
}else{
// set current grid data set to show as checkboxes in the filter page
filterDataSet = gr.jqGrid('getCol',columnName,false);
}
for(key in filterDataSet){
// check box element object that will hold the checkbox label and its state ( true / false)
chkBoxElement = new Object();
chkBoxElement.id = getValueFromArray(filterDataSet[key],columnName);
if(typeof(chkBoxElement.id)== 'undefined'){
break;
}
// if this id is saved in previous filtering event checked option will set to true.
if(typeof(selectedFilters[columnName]) != 'undefined'){
if (includeInArray(selectedFilters[columnName],chkBoxElement.id)){
chkBoxElement.selected = true;
}else{
chkBoxElement.selected = false;
}
}
colData.push(chkBoxElement);
}
// removing duplicates
var uniqueValues = removeDuplicates(colData);
// sort the array without duplicate with the custom comparator
uniqueValues.sort(sortComparator);
// open the filter screen. return type will captured in the 'seletedElements' variable as pipe separated string
seletedElements = window.showModalDialog(filterUrl,uniqueValues,"dialogWidth:400px;dialogHeight:250px;center:yes;resizable:no;status:no;help:no;");
if(seletedElements != null && seletedElements != 'null'){
// get selected values to the array
selectedFilters[columnName] = seletedElements.split("|");
}else{
//user just close the popup (using close button) will return without doing anything
return;
}
if(columnName == firstSortColumn){
// refine filter with the non filtered data set
refillGrid(seletedElements,columnName,originalData);
}else{
// send current data set to refine
var currentDataSet = gr.jqGrid('getGridParam','data');
refillGrid(seletedElements,columnName,currentDataSet);
}
}
function formatGridData(columnName){
var isFormatter = gr.jqGrid("getColProp",columnName);
if(typeof isFormatter.formatter !== 'undefined') {
if(jq.isFunction( isFormatter.formatter ) ) {
for(key in originalData){
var plainValue = originalData[key][columnName];
var formattedVal = isFormatter.formatter.call(null,plainValue,null,null,null);
originalData[key][columnName] = formattedVal;
}
}
}
}
function resetFilters(){
for(key in applyFilterColumnNames){
jq("#btn_"+applyFilterColumnNames[key]).button("option", {
//icons: { primary: this.checked ? 'ui-icon-check' : 'ui-icon-closethick' }
icons: { primary: 'ui-icon-gear'}
});
}
gr.jqGrid("setCaption",gridCaption);
refreshGrid(originalData);
originalData = null;
firstSortColumn = null;
selectedFilters = new Object();
}
function refillGrid(seletedElements,columnName,filterDataSet){
var filteredData= new Array();
var elementsArray;
try{
elementsArray = seletedElements.split("|");
}catch(e){
// this exception happens when user simply open the filter screen
// do nothing and close it.
trace('Error in filter splitting -'+e);
return;
}
// When user de-select all check boxes from the popup screen
if(elementsArray == ""){
refreshGrid(originalData);
return;
}
// refine the grid data according to the filters
var mydata = filterDataSet;
for(i=0;i<elementsArray.length;i++){
var filterElement = elementsArray[i];
for(j = 0;j<mydata.length;j++){
if(filterElement==getValueFromArray(mydata[j],columnName)){
filteredData.push(mydata[j]);
}
}
}
// change the button icon to indicate that the column is filtered
changeButtonIcon(columnName);
// update the column header to indicate sort by column
changeGridCaption(columnName);
// fill the grid according to the passed array
refreshGrid(filteredData);
}
function changeGridCaption(columnName){
// get columns name array
var columnNames = gr.jqGrid('getGridParam','colNames');
// get column model array
var colModel = gr.jqGrid('getGridParam','colModel');
var colModelIndex=null;
if (firstSortColumn == columnName){
for(key in colModel){
try{
if (colModel[key].name == firstSortColumn){
colModelIndex = key;
break;
}
}catch(e){}
}
if(colModelIndex != null){
var columnName = columnNames[colModelIndex];
gr.jqGrid("setCaption",gridCaption + " - Filtered based on : "+columnName);
}
}
}
function changeButtonIcon(columnName){
//change the button Icon
jq("#btn_"+columnName).button("option", {
//icons: { primary: this.checked ? 'ui-icon-check' : 'ui-icon-closethick' }
icons: { primary: 'ui-icon-link'}
});
}
function getValueFromArray(obj,columnName){
if(obj !=null && typeof(obj)!='undefined'){
// if obj param is string just return it
if(typeof obj =='string'){
return obj;
}else{
return obj[columnName];
}
}
}
function sortComparator(a,b){
try{
var aId = a.id.toLowerCase();
var bId = b.id.toLowerCase();
if (aId < bId) {return 1}
if (aId > bId) {return -1}
}catch(e){
return 0;
}
}
function includeInArray(arr,obj) {
//alert(arr);
return (arr.indexOf(obj) != -1);
}
function refreshGrid(results) {
gr.jqGrid('clearGridData')
.jqGrid('setGridParam', { data: results })
.trigger('reloadGrid');
}
function removeDuplicates(valueArray){
var arr = {};
for ( i=0; i < valueArray.length; i++ ){
if(valueArray[i].id != null){
arr[valueArray[i].id] = valueArray[i];
}
}
valueArray = new Array();
for ( key in arr ){
valueArray.push(arr[key]);
}
return valueArray;
}
If something wrong here please let me know.this solution is working fine. but i really appreciate the comments in therms of performance and code best practices.

Categories

Resources