Keep getting 'undefined, undefined' saved in local storage - javascript

I'm making a day planner app with hour blocks from 0900-1700 where the inputs can be saved into local storage and then are automatically retrieved on page refresh. Having issues with my code currently with it only saving 'undefined, undefined' in the console, and not returning anything on page refresh. Any help is appreciated. Thanks!
HTML:
<tr class="row" id="15">
<th scope="time" id="hour15" class="time">15:00</th>
<td><input type="text" class= "hourinput"/></td>
<td class="btnContainer">
<button class="saveBtn"><i class="fas fa-save"></i></button>
</td>
</tr>
<tr class="row" id="16">
<th scope="time" id="hour16" class="time">16:00</th>
<td><input type="text" class= "hourinput"/></td>
<td class="btnContainer">
<button class="saveBtn"><i class="fas fa-save"></i></button>
</td>
</tr>
JS:
// Moment.js to auto-update time on webpage------------------------------------------//
var update = function () {
date = moment(new Date());
currentDay.html(date.format('dddd, MMMM Do YYYY, HH:mm:ss a'));
};
$(document).ready(function(){
currentDay = $('#currentDay');
update();
setInterval(update, 1000);
});
// Add input to local storage-------------------------------------------------------//
$('.saveBtn').on('click', function () {
// Get the values
var hourinput = $(this).siblings('.hourinput').val();
var hour = $(this).parent().attr('id');
// Save data in local storage
localStorage.setItem(hour, hourinput);
});
$('#9 .hourinput').val(localStorage.getItem('9'));
$('#10 .hourinput').val(localStorage.getItem('10'));
$('#11 .hourinput').val(localStorage.getItem('11'));
$('#12 .hourinput').val(localStorage.getItem('12'));
$('#13 .hourinput').val(localStorage.getItem('13'));
$('#14 .hourinput').val(localStorage.getItem('14'));
$('#15 .hourinput').val(localStorage.getItem('15'));
$('#16 .hourinput').val(localStorage.getItem('16'));
$('#17 .hourinput').val(localStorage.getItem('17'));

Your .saveBtn elements have no siblings. You'll need to traverse up to the .row and then locate the elements / values within.
For example
$(".saveBtn").on("click", function () {
const row = $(this).closest(".row") // see https://api.jquery.com/closest/
// Get the values
const hourinput = row.find(".hourinput").val();
const hour = row.attr('id');
// Save data in local storage
localStorage.setItem(hour, hourinput);
});
FYI, your click event handler could be more efficient by listening at the container level (eg your <table>)
$("table#hours").on("click", ".row[id] .saveBtn", function() {
// etc
})
You should also make your buttons type="button" to make sure they don't accidentally submit any forms.

Related

Add to favorites/bookmark using HTML5 localStorage and jQuery

I want to add 'add to favorites/bookmark' feature in one of my projects, but am totally blank regarding the same.
Basically, I'm using bootstrap glyphicons for user to select it if he wants add/remove from favorites. I did some research and found html5 localStorage concept suitable but can't really figure out its exact working for my project. It would be a great help if anyone here can guide me on it.
here's html:
<h1>test</h1>
<table class="'basic">
<tr>
<td><div class="glyphicon glyphicon-star-empty icon bkmark_icon"> </div></td>
<td>A</td>
</tr>
<tr>
<td><div class="glyphicon glyphicon-star-empty icon bkmark_icon"> </div></td>
<td>B</td>
</tr>
<tr>
<td><div class="glyphicon glyphicon-star-empty icon bkmark_icon"> </div></td>
<td>C</td>
</tr>
</table>
<br><button class="btn">You have selected:</button>
since I don't really know the implementation of localStorage in jQuery, haven't added it, yet this is what js file has for now:
$(function() {
$(document).on('click', '.bkmark_icon', function(){
$(this).toggleClass('glyphicon-star-empty glyphicon-star');
// localStorage.setItem('display', $(this).is(':visible'));
});
$(document).on('click', '.btn', function(){
var bkmark_item = '<table><tr><td><div class="glyphicon glyphicon-star icon bkmark_icon"></div></td><td>*selected*</td></tr></table>';
$(bkmark_item).insertAfter('h1');
});
});
i did search over it and found this stack overflow answer appropriate.
what I need?
when user clicks on glyphicon-star-empty, it should toggle to glyphicon-star and the related item should be added to localStorage (i.e favorites).
when user clicks on 'You have selected:' button, it should remove current content which is in table and show only the favorited items(on the same page) with an option to un-favorite it.
here's fiddle the i'm working on.
Try creating a JavaScript object and serialize it to save it in localStorage. Use something like this -
var bookmarkedItems = [];
function ItemObject(name, content)
{
this.name = name;
this.content = content;
}
function addItem()
{
bookmarkedItems.push(new ItemObject('Item1', 'Content1'));
}
function saveToLocalStorage(item)
{
var ob = localStorage.get('KEY');
if(ob)
{
bookmarkedItems = JSON.parse(ob);
}
bookmarkedItems.push(item);
localStorage.set('KEY', JSON.stringify(bookmarkedItems);
}
OR
Refer below code -
var storageService = function () {
var STORAGE_KEY = "bookmarkitems";
var bookmarkitems = {};
var init = function () {
bookmarkitems = sessionStorage.getItem(STORAGE_KEY);
if (bookmarkitems) {
bookmarkitems = JSON.parse(bookmarkitems);
}
else {
bookmarkitems = {};
}
};
var set = function (key, value) {
bookmarkitems[key] = value;
updateStorage();
};
var get = function (key) {
return bookmarkitems[key];
};
var updateStorage = function () {
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(bookmarkitems));
};
return {
init: init,
set: set,
get: get,
updateStorage: updateStorage
};
};
Here is a small example on how to use local storage:
// Store
localStorage.setItem("lastname", "Smith");
// Retrieve
document.getElementById("result").innerHTML = localStorage.getItem("lastname");
You can reference this page for more examples.
Using it is pretty simple it works like any JS Object.
EDIT:
There are more extended examples on the functionality of local storage here.

create an automatic bold for table by the ID ?? with javascript

first of all I apologize for my bad English, I want to make a JavaScript for a tabele who makes himself automatically by the ID Bold, just like this one here but the code is not only for weeks for tabele
the table has therefore different time input I will when the time is for example 08:00 clock, the tabele from 08:15 to mark Irish always +1
<td id="1">08:00</td>
<td id="1">BEKA-KAQANIK</td>
</tr>
<tr>
<td id="2">08:15</td>
<td id="2">MEDINA</td>
Here is an example but it is only on weekdays
http://jsfiddle.net/c5bHx/
var days = 'sunday,monday,tuesday,wednesday,thursday,friday,saturday'.split(',');
document.getElementById( days[(new Date()).getDay()] ).className = 'bold';
.bold {
font-weight:bold;
}
<div id="monday">Monday: 12:00-2:00</div>
<div id="tuesday">Tuesday: 11:00-3:00</div>
<div id="wednesday">wednesday: 12:00-2:00</div>
<div id="thursday">thursday: 11:00-3:00</div>
<div id="friday">friday: 12:00-2:00</div>
<div id="saturday">saturday: 11:00-3:00</div>
<div id="sunday">sunday: 12:00-2:00</div>
I'm not sure if I understand your question correctly, but here is an example JSFIDDLE. It might help with what you're trying to accomplish.
<table>
<tr id="1530">
<td>15:30</td>
<td>A</td>
</tr>
<tr id="1545">
<td>15:45</td>
<td>B</td>
</tr>
<tr id="1600">
<td>16:00</td>
<td>C</td>
</tr>
</table>
// Initialize new Date object.
var currentDate = new Date();
// Get the hour
var currentHour = currentDate.getHours();
// Get the minutes
var currentMinute = currentDate.getMinutes();
// Bin the minutes to 15 minute increments by using modulus
// For example, xx:33 becomes 30
var minuteBin = currentMinute - (currentMinute % 15);
// Create a string that matches the HTML ids
var idString = "" + currentHour + minuteBin;
// Set the matching div class to 'bold'
document.getElementById(idString).className = 'bold';
// Log variables to console for debugging
console.log("Time =",currentHour,":",currentMinute,"bin =",minuteBin,"idString =",idString);
This example is meant for GMT-0400 (EDT). This will give different results in different time zones.
If I've misunderstood anything, please let me know and I will do my best to update my answer. Hope that helps!

$interval happening too many times

Hopefully I can explain this so you can understand. I just finished up a question getting help with angular's $interval functionality. Let's start from the basics first:
I have a dropdown where a user selects an option.
That action calls a select method which makes a $http.get( )
request.
The resulting data is then placed into a list using mg-repeat.
The data can be updated from another service, so I need this list to
periodically poll and refresh the list, enter $interval
In this code below, I am close, but not quite there. Say I want to refresh the list once every 10 seconds, if I choose option 1 from the start, it will refresh option 1's list every 10 seconds. Great right?
Now if I choose option 2, in terms that I understand, it seems like it creates another thread. It changes the $http.get( ) where it goes from option 1 to option 2, but it keeps option 1's $interval thread open. So it pings option 2's $http.get( ) twice in 10 seconds. Once following the time interval of the first request ever(for option 1) and once in the interval of me selecting option 2.
Here is the JS code for the select function. This happens when a user selects something from the dropdown:
$scope.select = function() {
$scope.searchText = '';
$scope.selectedItem = null;
var url = 'http:xxxxxxxxxxxx.com';
url += $scope.selectModel.name;
console.debug("GOING TO: " + url);
$http.get(url).success(function(data2) {
$scope.records = [];
data2.forEach(function(r) {
$scope.records.push(r);
});
});
$interval(function() {
$http.get(url).success(function(data2) {
$scope.records = [];
data2.forEach(function(r) {
$scope.records.push(r);
});
});
}, 30000);
};
And here is the section of html in question:
<div style="margin: 1em">
<h4>Search</h4>
<div role="form">
<!-- start dropdown -->
<div class="form-group">
<select class="form-control" ng-options="model as model.name for model in allModels" ng-model="selectModel" ng-change="select()">
<option value="">Choose Model</option>
</select>
</div>
<!-- /end dropdown-->
<div class="form-group">
<input id="start_date" type="text" class="form-control" placeholder="Threat Date">
</div>
</div>
<div>
<table class="table table-hover table-striped" ng-show="records">
<thead>
<th>#</th>
<th>Name</th>
<th>Score</th>
</thead>
<tr data-ng-repeat=" item in records | orderBy : '-score' | limitTo : 10 " ng-click="moreInfo(item)">
<td>{{$index+1}}</td>
<td>{{item.name.slice(5)}}</td>
<td>{{item.score.toFixed(3)}}</td>
</tr>
</table>
</div>
</div>
Let me know if i need to clarify some. Thanks.
You need to cancel your interval.
// Activate
var myInterval = $interval(....);
// Deactivate
$interval.cancel(myInterval);
myInterval = undefined; // Necessary for conditional checking

Alternative method to get data in jQuery than to use parent() and next() repeatedly?

I have an HTML Table of Task List Data that I am trying to get all the data values and store them to an object when a row is clicked on.
I have a demo of some HTML and the JavaScript below that is all functioning just as I need it.
The problem is that I know the jQuery part is really bad quality as it calls things like this...
$taskEl.parent().parent('td').next().next().next().text()
I feel these can be improved but I am not sure how so. Most of this was already done on an existing project that I am trying to clean up and this 1 section is really bugging me.
I would appreciate any help in alternative ways to get the data please?
Or if this is the most efficient way?
Also if I need to I have access to modify some of the HTML if need to add new ID's or data attributes.
JSFiddle demo...when you click a link in the Task Title, it will print the values that it selected to the DOM for demo puirposes...: DEMO
Demo JavaScript to get Task Data from the DOM Task List and create a JS Object with it:
//Open Task Modal when a Task record is clicked in Task List
$('body').on('click', '.taskName', function() {
// Set and Cache Task ID from clicked on Task Item
var taskId = $(this).parent().parent().parent().dataAttr('task-id');
var $taskEl = $(this);
// Populate Task Data Object from DOM values
taskDataObject = {
//projectId: projectTaskModal.cache.projectId,
taskId: taskId,
taskName: $taskEl.text(),
taskDescription: $taskEl.next('.description').text(),
taskStatus: $taskEl.parent().parent('td').next().text(),
taskPriority: $taskEl.parent().parent('td').next().next().text(),
taskTags: $taskEl.parent().parent('td').next().next().next().text(),
taskCreatedDate: $taskEl.parent().parent('td').next().next().next().next().text(),
taskModifiedDate: $taskEl.parent().parent('td').next().next().next().next().next().text(),
taskDueDate: $taskEl.parent().parent('td').next().next().next().next().next().next().text(),
};
});
Demo Task List HTML
<span id="projectIdPlaceholder" data-project-id="1234"></span>
<table>
<!-- test task list record 1 -->
<tr id="task-row-1414135033730" data-task-id="1414135033730">
<td width="1%" class="task-checkbox">
<div class="status_update status-checkbox-Not-Started" data-id="1414135033730" data-status="Not Started" id="1414135033730"></div>
</td>
<td width="59%" class="task-name">
<div><span id="1414135033730-taskName" class="taskName strikethrough">Add a Plugin System similar to WordPress Action and Filter Hooks
<span class="open-description-icon open-description-icon-close" title"toggle="" description="" view"="">+</span>
</span>
<div id="1414135033730-taskDescription" class="description" style="display: block;">Project module will Fire Events before and After key events and Plugins in a custom/modulename/plugins/ folder will load and be able to Listen for these Event Hooks and then run it;s own code before and after these actions are executed!</div>
</div>
</td>
<td width="10%">
<div id="1414135033730-status" class="Not Started status"> Not Started</div>
</td>
<td width="10%">
<div id="1414135033730-taskPriority" class="priority">Low</div>
</td>
<td width="10%">
<div class="type">Other</div>
</td>
<td width="10%">
<div id="1414135033730-createdDate" class="createdDate">2014-10-24 07:18:41</div>
</td>
<td width="10%">
<div id="1414135033730-modifiedDate" class="modifiedDate">2014-10-24 07:18:41</div>
</td>
<td width="10%">
<div id="1414135033730-dueDate" class="dueDate">None</div>
</td>
</tr>
<!-- test task list record 2 -->
<tr id="task-row-1414135033731" data-task-id="1414135033731">
<td width="1%" class="task-checkbox">
<div class="status_update status-checkbox-Completed" data-id="1414135033731" data-status="Completed" id="1414135033731"></div>
</td>
<td width="59%" class="task-name">
<div>
<span id="1414135033731-taskName" class="taskName">Testing Task Record Number 2
<span class="open-description-icon open-description-icon-close" title"toggle="" description="" view"="">+</span>
</span>
<div id="1414135033731-taskDescription" class="description" style="display: block;">My project task description for demo testing task record number 2!</div>
</div>
</td>
<td width="10%">
<div id="1414135033731-status" class="Completed status">Completed</div>
</td>
<td width="10%">
<div id="1414135033731-taskPriority" class="priority">High</div>
</td>
<td width="10%">
<div class="type">Magento</div>
</td>
<td width="10%">
<div id="1414135033731-createdDate" class="createdDate">2014-10-27 03:10:14</div>
</td>
<td width="10%">
<div id="1414135033731-modifiedDate" class="modifiedDate">2014-10-27 03:22:24</div>
</td>
<td width="10%">
<div id="1414135033731-dueDate" class="dueDate">06/21/2015</div>
</td>
</tr>
</table>
Since you have Task ID available and the divs all have ID's, I would target the element ID's directly. In jQuery, the more specific you can be, the better.
$('body').on('click', '.taskName', function() {
// Get the task (row) that will be used for running all the selections
var taskid = $(this).closest("tr").dataAttr('task-id');
var taskSel = "#" + taskid + "-";
// Populate Task Data Object from DOM values
taskDataObject = {
taskId: taskid;,
taskName: $(taskSel + "taskName").text(),
taskDescription: $(taskSel + "taskDescription").text(),
taskStatus: $(taskSel + "taskStatus").text(),
taskPriority: $(taskSel + "taskPriority").text(),
taskTags: $(taskSel + "taskTags").text(),
taskCreatedDate: $(taskSel + "taskCreatedDate").text(),
taskModifiedDate: $(taskSel + "taskModifiedDate").text(),
taskDueDate: $(taskSel + "taskDueDate").text(),
};
});
Your different values are in div and span with a descriptive class name, you could just select them using find() and their className within the row that was clicked.
Something like this:
//Open Task Modal when a Task record is clicked in Task List
$('body').on('click', '.taskName', function() {
// Get the task (row) that will be used for running all the selections
$task = $(this).closest("tr");
// Populate Task Data Object from DOM values
taskDataObject = {
//projectId: projectTaskModal.cache.projectId,
taskId: $task.data('task-id'),
taskName: $task.find(".taskName").text(),
taskDescription: $task.find(".description").text(),
taskStatus: $task.find(".status").text(),
taskPriority: $task.find(".priority").text(),
taskTags: $task.find(".type").text(),
taskCreatedDate: $task.find(".createdDate").text(),
taskModifiedDate: $task.find(".modifiedDate").text(),
taskDueDate: $task.find(".dueDate").text()
};
});
Edit: To be consistent, I replaced $(this).text() with $task.find(".taskName").text(), and $(this).next(".description").text() with $task.find(".description").text(). And removed taskId and taskEl as they were redundant.
Edit2: Replaced $(this).parent().parent().parent() with $(this).closest("tr"). That way if the HTML structure changes in the future (and the number of parents change), still the task row will be selected and the code should work without issues.
Instead of manually selecting each element, I suggest you to use data-* attributes to store values and use JavaScript to dynamically build the object, for example:
HTML:
<table id="table">
<tr>
<td data-name="taskName" data-value="Test">
<div class="foo">Test</div>
</td>
<td data-name="taskDate" data-value="1439275213">
<div class="foo">2014-10-24 07:18:41</div>
</td>
</tr>
</table>
JavaScript:
var $nodes = $('#table').find('td[data-name]'); // find TDs with 'data-attr'
var attributes = {};
$nodes.each(function() { // generate object with all data-name/data-value pairs
var $node = $(this);
attributes[$node.attr('data-name')] = $node.attr('data-value');
});
console.log(attributes); // prints { taskName: "Test", taskDate: "1439275213" }
Demo: http://jsfiddle.net/andunai/uu65ntks/
P. S. This method will also allow you to display values different from their value, for example, to display human-readable date, but to serialize it as unix timestamp.
There are various options here, depends on what you need,
This example is not the fastest but is closed to best performance,
great usage of this is reloading DOM element from $ selectors, meaning that parallel events processing the DOM will render same thing,
instead of $this = $(this), reelect your dom element, again not the best practice in term of performance (search in dom), still provides the best results over dynamic modified html.
Your call:
$('body').on('click', '.taskName', function() {
var taskId = $(this).attr('id').replace('-taskName', '');
taskDataObject = {
//projectId: projectTaskModal.cache.projectId,
taskId: taskId,
taskName: $(this).text(),
taskDescription:$('[id="' + taskId + '-taskDescription"').text(),
taskStatus:$('[id="' + taskId + '-status"').text(),
taskPriority: $('[id="' + taskId + '-taskPriority"').text(),
taskTags: "undefined please defeine corect atribute on div",
taskCreatedDate: $('[id="' + taskId + '-createdDate"').text(),
taskModifiedDate: $('[id="' + taskId + '-modifiedDate"').text(),
taskDueDate: $('[id="' + taskId + '-dueDate"').text(),
};
deepTrim(taskDataObject);
printObjectToDom(taskDataObject);
});
you can write custom selector over your main parent html, similar with my example
var T_REX = $(this).parent().parent()... whatever;
var T_REX_CUBS = TREX.children();
var taskname = T_REX_CUBS[0].find("div.taskName").text();
or the simplest ones
var T_REX = $(this).closest('tr');
var taskid = T_REX.attr('data-task-id');
var taskname = T_REX.find("div.taskName").text();
Now the fastest option is to save the main parent object, over that apply jquery custom selectors, but this is not the recommend if your data from table is changing real time.

knockout observable array is not updating view on removing elements from array

Here is my view model code
var TopicsViewModel = function() {
var self = this;
var fakeTopicData =
[
];
self.createProfile = function () {
alert("came to create profile");
};
self.editProfile = function () {
alert("came to edit profile");
};
self.removeProfile = function (profile) {
alert("came to remove profile");
fakeTopicData.pop();
self.topicsArr(fakeTopicData);
};
var refresh = function() {
self.topicsArr = fakeTopicData;
};
self.topicsArr = ko.observableArray([]);
refresh();
};
ko.applyBindings(new TopicsViewModel());
Here is my html for the view:
<hr />
<hr />
<table class="table table-striped table-bordered table-condensed">
<tr >
<th>Area</th>
<th>Name</th>
<th>Link</th>
<th>Description</th>
<th>Why</th>
</tr>
<tbody data-bind="foreach : topicsArr">
<tr>
<td data-bind="text :area"> </td>
<td class=""><a data-bind="text:name, click:$parent.editProfile"></a></td>
<td data-bind="text:link"> </td>
<td data-bind="text:desc"> </td>
<td data-bind="text:why" ></td>
<td><button class="btn btn-mini btn-danger" data-bind="click:$parent.removeProfile">remove</button></td>
</tr>
</tbody>
</table>
<script src="~/Scripts/Topic.js"></script>
The view initially display all the Topics in my fakeData Array.
On clicking the remove Button, I am trying to remove an element from the array, and expected the view to refresh and not show the removed item any more. However the view still shows all the 3 topics.
Could someone please point to what I might be doing wrong.
I spend a long time researching the other similar queries on stackoverflow, but am still stuck. Thanks so much for any insight into this issue.
You are replacing your observable array called topicsarr with one which isn't observable in your refresh method...
Change
var refresh = function() {
self.topicsArr = fakeTopicData;
};
to
var refresh = function() {
self.topicsArr(fakeTopicData);
};
you have 2 issues in your code.
First, you are setting your observableArray topicsArr with non observableArray or normal array in refresh function. Instead use self.topicsArr(fakeTopicData)
Second, in function removeProfile you are using pop() to remove profile element. From KnockoutJS documentation:
myObservableArray.pop() removes the last value from the array and
returns it
So, it's better to use remove(item) and pass to it your profile element or loop through your array and remove that specific item
myObservableArray.remove(someItem) removes all values that equal
someItem and returns them as an array

Categories

Resources