I'm trying to make a todo list and store it in local storage so it gets saved.
I run the get() and list() function on startup to pull it out of localStorage and list it. Problem is that the for loop won't run in the list() function. Once I put in a new item and run the newItem() function it pulls out of localStorage and lists it all fine. Any ideas?
get();
list();
function Todo(name){
this.name = name;
this.completed = false;
}
function newItem(){
var t = new Todo(document.getElementById("newItem").value)
items.push(t)
save();
console.log(items)
}
function save(){
var save = JSON.stringify(items)
localStorage.setItem("localsave", save)
list();
}
function list(name){
var html = "";
console.log(items)
for(var i in items){
var todo = items[i];
var name = todo.name
var completed = todo.completed;
html += "<li>"+name+""+completed+"</li>"
}
$("#ul").html(html);
}
function get(){
var temp = localStorage.getItem("localsave")
items = JSON.parse(temp)
}
HTML document looks like this if anyone is interested in that
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<script
src="https://code.jquery.com/jquery-3.3.1.js"
integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
crossorigin="anonymous"></script>
<script src="todo.js"></script>
<form method="post" action="javascript:newItem()">
<input type="text" id="newItem" name="newItem" placeholder="New item">
</form>
<ul id="ul">
</ul>
your code runs the java script code first then it renders the HTMl elements.
this line had been executed first , before the control with "ul" id was rendered , so it has fetched the data from storage already but can't view them in the not rendered "ui".
$("#ul").html(html);
so your code should call todo.js after rendering the HTML elements like that:
<html>
<body>
<script
src="https://code.jquery.com/jquery-3.3.1.js"
integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
crossorigin="anonymous"></script>
<form method="post" action="javascript:newItem()">
<input type="text" id="newItem" name="newItem" placeholder="New item">
</form>
<ul id="ul">
</ul>
<script src="todo.js"></script>
</body>
</html>
As #Jonas Wilms mentioned you need to handle the null value from store. Your get function needs to be something like below.
get() {
var temp = localStorage.getItem("localsave")
if (temp) {
items = JSON.parse(temp)
}
else {
items = [];
}
}
I think this is you want.
list();
function Todo(name){
this.name = name;
this.completed = false;
}
function newItem(){
var items = get();
var t = new Todo(document.getElementById("newItem").value)
items.push(t);
save(items);
console.log('saving items', items);
}
function save(items){
var save = JSON.stringify(items)
localStorage.setItem("localsave", save)
list();
}
function list(name){
var html = "";
var items = get();
if(items.length > 0){
for(var i in items){
var todo = items[i];
var name = todo.name;
var completed = todo.completed;
html += "<li>"+name+""+completed+"</li>"
}
$("#ul").html(html);
}
console.log('listing items', items);
}
function get(){
var temp = localStorage.getItem("localsave");
if(temp){
return JSON.parse(temp);
}else{
return [];
}
}
Related
I am trying to create a to-do list in HTML, CSS and pure JS.
const dSubmit = document.getElementById('submit');
const storeData = [];
let typer = document.getElementById('type');
let input = document.getElementById('text');
const list = document.getElementById('listHolder');
dSubmit.addEventListener("click", (e) => {
e.preventDefault();
if (input.value == "") {
typer.innerHTML = "Please enter a task";
} else {
typer.innerHTML = "";
store();
}
});
function store() {
const tData = document.getElementById('text').value;
storeData.push(tData);
updater();
input.value = "";
}
function deleter (index) {
storeData.splice(index, 1);
updater();
}
function updater() {
let htmlCode = "";
storeData.forEach(function(item, index){
htmlCode += "<div class='test'><div id = "+ index +">" + item + "</div><div class='sideBtn'><button type='button' class='edit' onClick= 'editF("+ index +")'>Edit</button><button class='delBtn' onClick= 'deleter("+ index +")'>Delete</button> </div> </div>"
})
list.innerHTML = htmlCode;
}
function editF (index) {
let tempOne = document.getElementById(index);
let tempTwo = "<input id='inputText"+String(index)+"' type='text' name='task' value ='" + String(storeData[index]) + "'><button id='saveText"+String(index)+"' onClick= 'save("+index+")' >Save</button>"
tempOne.innerHTML = tempTwo;
}
function save (index) {
console.log('test1')
let tempOne= document.getElementById('saveText'+String(index));
let tempTwo = document.getElementById('inputText'+String(index));
console.log('test2')
tempOne.addEventListener("click", function foo (){
console.log('test3')
storeData.splice(index,1,tempTwo.value)
updater()
}
)
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8">
<title>To Do List</title>
</head>
<body>
<h1>To-do-list</h1>
<form>
<label for="task">Please enter item:</label>
<input type="text" name="task" id="text">
<button id="submit">Submit</button>
</form>
<div id='type'></div>
<div>List:</div>
<div id="listHolder" class="test"></div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
I am facing problems with the save function. If I edit an item in the to-do list and click the save button, the function executes up to the point of console.log('test2'). If I click save again the function executes in its entirety.
I would like to ask why the first click results in execution of the save function up to 'test2'?
Additionally would anyone be kind enough to critique my JS? are there things in dire need of improvement? or is there a more practical/efficient method of writing my JS code?
Thank you for your help in advance.
After the 'test2' log, you are adding an event listener, and the rest of the code is inside of the listener block. The code in the listener block is only executed once that listener receives a 'click' event, which is why it works the second time.
I received this code from another user in this forum.
Issue: As seen in the below screenshot, the search results (or data) starts to appear when you click or start typing in the search box or else only the search box loads without the data.
Requirement: I want to display the results (or data) as the page loads.
The code is given below
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<style>
.nav-link {
cursor: pointer;
}
</style>
</head>
<body>
<div class="container">
<ul class="nav nav-tabs">
<li class="nav-item">
<div class="nav-link"id="search-link">Search</div>
</li>
</ul>
<div id="app"></div>
<!-- Content here -->
</div>
<!-- Option 1: jQuery and Bootstrap Bundle (includes Popper) -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
<script>
var data;
function loadView(options){
var id = typeof options.id === "undefined" ? "app" : options.id;
var cb = typeof options.callback === "undefined" ? function(){} : options.callback;
google.script.run.withSuccessHandler(function(html){
document.getElementById("app").innerHTML = html;
typeof options.params === "undefined" ? cb() : cb(options.params);
})[options.func]();
}
function setDataForSearch(){
google.script.run.withSuccessHandler(function(dataReturned){
data = dataReturned.slice();
}).getDataForSearch();
}
function search(){
var searchinput = document.getElementById("searchinput").value.toString().toLowerCase().trim();
var searchWords = searchinput.split(/\s+/);
var searchColumns = [0,1,2,3,4,5,6,7];
// and or
var resultsArray = data.filter(function(r){
return searchWords.every(function(word){
return searchColumns.some(function(colIndex){
return r[colIndex].toString().toLowerCase().indexOf(word) !== -1
});
});
});
var searchResultsBox = document.getElementById("searchResults");
var templateBox = document.getElementById("rowTemplate");
var template = templateBox.content;
searchResultsBox.innerHTML = "";
resultsArray.forEach(function(r){
var tr = template.cloneNode(true);
var hinmokuColumn = tr.querySelector(".hinmoku");
var buhinCodeuColumn = tr.querySelector(".buhinCode");
var buhinNameColumn = tr.querySelector(".buhinName");
var hitsuyoColumn = tr.querySelector(".hitsuyo");
var genkaColumn = tr.querySelector(".genka");
var kobaiColumn = tr.querySelector(".kobai");
var sagakuColumn = tr.querySelector(".sagaku");
var kenshoColumn = tr.querySelector(".kensho");
hinmokuColumn.textContent = r[0];
buhinCodeuColumn.textContent = r[1];
buhinNameColumn.textContent = r[2];
hitsuyoColumn.textContent = r[3];
genkaColumn.textContent = r[4];
kobaiColumn.textContent = r[5];
sagakuColumn.textContent = r[6];
kenshoColumn.textContent = r[7];
searchResultsBox.appendChild(tr);
});
}
function loadSearchView(){
loadView({func:"loadSearchView", callback: setDataForSearch});
}
window.addEventListener("load", loadSearchView);
function inputEventHandler(e){
if (e.target.matches("#searchinput")){
search();
}
}
document.getElementById("app").addEventListener("input",inputEventHandler);
document.getElementById("app").addEventListener("click",inputEventHandler);
</script>
</body>
</html>
server-side code
function getDataForSearch(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("TableData");
return ws.getRange(2, 1, ws.getLastRow(),8).getValues();
}
I need to know what modification needs to be done in the code?
I tried document.getElementById("app").addEventListener("load",inputEventHandler);
but it didn't work.
is there any other event listeners available that will load the search results (or data) (without taking any action on the site, i mean without clicking or typing in the search box)?
Thanks in advance.
Edit: loadsearchview function file code
function loadSearchView(){
return loadPartialHTML_("search");
}
You could use addEventListener with DOMContentLoaded to call a function when all the HTML is loaded and the DOM tree is built. For your particular situation, here's how I managed:
First I need to load data into data variable and call the loadSearchView() function when the page loads:
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function () {
google.script.run.withSuccessHandler(function (r) {
data = r;
loadSearchView();
}).getDataForSearch();
});
} else {
google.script.run.withSuccessHandler(function (r) {
data = r;
loadSearchView();
}).getDataForSearch();
}
Then I need to load the search view, but instead of calling setDataForSearch, I implemented another function to call functions after this view is loaded. This might be useful if you want to call more than one function after the searchView loads. So basically the code would be like this:
function loadSearchView() {
loadView({ func: "loadSearchView", callback: afterSearchViewLoads });
}
function afterSearchViewLoads(){
loadDataWhenPageLoads();
}
function loadDataWhenPageLoads(){
var resultArray = data;
var searchResultsBox = document.getElementById("searchResults");
var templateBox = document.getElementById("rowTemplate");
var template = templateBox.content;
searchResultsBox.innerHTML = "";
resultsArray.forEach(function (r) {
var tr = template.cloneNode(true);
var hinmokuColumn = tr.querySelector(".hinmoku");
var buhinCodeuColumn = tr.querySelector(".buhinCode");
var buhinNameColumn = tr.querySelector(".buhinName");
var hitsuyoColumn = tr.querySelector(".hitsuyo");
var genkaColumn = tr.querySelector(".genka");
var kobaiColumn = tr.querySelector(".kobai");
var sagakuColumn = tr.querySelector(".sagaku");
var kenshoColumn = tr.querySelector(".kensho");
hinmokuColumn.textContent = r[0];
buhinCodeuColumn.textContent = r[1];
buhinNameColumn.textContent = r[2];
hitsuyoColumn.textContent = r[3];
genkaColumn.textContent = r[4];
kobaiColumn.textContent = r[5];
sagakuColumn.textContent = r[6];
kenshoColumn.textContent = r[7];
searchResultsBox.appendChild(tr);
});
}
Hope this can solve your problem!
AddEventListener when you click enter key in keyboard will help you. Link: EventListener Enter Key
Also addEventListener "change" will help you.
edit
If you want your data to load when page is loaded use one of those ways:
window.onload = function() {
Search();
} // way one
window.onload = Search(); //way two
<body onclick="Search()"> // way three
I'm trying to add ordered list items depending on what a user enters in window.prompt(). Is this possible?
Below is my code. Sorry if this is messy, I'm fairly new to this. Any help is appreciated!
<!DOCTYPE = html>
<head>
<script type = "text/javascript">
var test = document.getElementById('list');
var item1 = window.prompt("Enter first item:");
if (item1 != null) {
function listAdd() {
var entry = document.createElement('li');
entry.appendChild(document.createTextNode(item1));
list.appendChild(entry);
}
}
var item2 = window.prompt("Enter second item");
if (item2 != null) {
function listAdd() {
var entry = document.createElement('li');
entry.appendChild(document.createTextNode(item2));
list.appendChild(entry);
}
}
</script>
</head>
<body>
<strong>Your two items:</strong>
<ol id="list">
</ol>
</body>
Things I fixed: got rid of the function listAdd and moved the code directly into the if clause, renamed test as list (misnamed variable), and moved the script into the body so the html nodes exist when it runs.
<!DOCTYPE = html>
<head>
</head>
<body>
<strong>Your two items:</strong>
<ol id="list">
</ol>
<script type = "text/javascript">
var list = document.getElementById('list');
var item1 = window.prompt("Enter first item:");
if (item1 != null) {
var entry = document.createElement('li');
entry.appendChild(document.createTextNode(item1));
list.appendChild(entry);
}
var item2 = window.prompt("Enter second item");
if (item2 != null) {
var entry = document.createElement('li');
entry.appendChild(document.createTextNode(item2));
list.appendChild(entry);
}
</script>
</body>
Your code wraps a function in an if. That's not right - you are declaring the function there, not running it. The result is that nothing happens. You could improve the code a little by declaring the listAdd function first, then calling it after each prompt, passing in the parameter from the prompt.
You can try removing the function and you mistakenly set list.appendChild(entry) instead of test.appendChild(entry) because we called the ordered list item id and set it to the test variable.
<!DOCTYPE=html>
<body>
<strong>Your two items:</strong>
<ol id="list" >
</ol>
<script type = "text/javascript">
var test = document.getElementById('list');
var item1 = window.prompt("Enter first item:");
var item2 = window.prompt("Enter second item");
if (item1 != null ) {
var entry = document.createElement('li');
entry.appendChild(document.createTextNode(item1));
test.appendChild(entry);
}
if (item2 != null ) {
var entry = document.createElement('li');
entry.appendChild(document.createTextNode(item2));
test.appendChild(entry);
}
</script>
</body>
var value1 = document.getElementById('list');
var value1 = window.prompt("Enter first item:");
if (value1 != null) {
listAdd(value1);
}
var value2 = window.prompt("Enter second item");
if (value2 != null) {
listAdd(value2);
}
function listAdd(textValue) {
var entry = document.createElement('li');
entry.appendChild(document.createTextNode(textValue));
list.appendChild(entry);
}
<!DOCTYPE = html>
<head>
</head>
<body>
<strong>Your two items:</strong>
<ol id="list">
</ol>
</body>
Created a generic function to add values in the List:
This is also used to reduce code.
Sure you can
This is one way
<body>
<ul id='myList'>
<li> Item One </li>
</ul>
<script>
let myList = document.getElementById('myList');
function makeUserLi(userPrompt){
console.log(userPrompt)
let userItem = document.createElement('li')
userItem.innerText = userPrompt ?? 'no text given';
myList.append(userItem);
}
makeUserLi(window.prompt('Add A List Item'))
</script>
</body>
Here is a working codepen
CodePen
I made a chrome extension where my popup button calls a script. The other script uses jQuery but I get an error saying jQuery is not defined.
My popup.html:
<!DOCTYPE html>
<html>
<head>
<title>HomAttendance</title>
</head>
<body>
<h1 style="color:#E54E4E">Hom<span style="color:#4E97E5">Attendance</span></h1>
<button type id="record" style="background-color:White"><h1 style="color:Black">Record Attendance</h1></button>
</body>
<script src="jquery-3.4.1.min.js"></script>
<script src="popup.js"></script>
</html>
My popup.js:
document.addEventListener('DOMContentLoaded', function() {
var login = document.getElementById('record');
login.addEventListener('click', function() {
chrome.tabs.executeScript({file: 'markStudents.js'});
});
});
myScript.js:
var arrays = []
$.get('Attendance.txt', function(data){
var splitted = data.split("\n"); // --> should return an array for each line
// Loop through all lines
for(var i = 0; i < splitted.length; i++)
{
var line = splitted[i];
// Now you could remove [ and ] from string
var removed = line.replace('[','').replace(']','');
var refined = removed.replace(' ', '');
// Now you can split all values by using , delimiter
var values = refined.split(',');
var array = [];
// Now you can iterate through all values and add them to your array
for(var c = 0; c < values.length; c++)
{
var value = values[c];
array.push(value);
}
arrays.push(array);
}
});
var present = arrays[0];
console.log(present);
var absent = arrays[1];
console.log(absent);
var user = present[0];
var pass = absent[0];
var loginField = document.getElementById('fieldAccount');
var passwordField = document.getElementById('fieldPassword');
loginField.value = user;
passwordField.value = pass;
var loginForm = document.getElementById('btn-enter-sign-in');
Is there any way to include my jquery.js in myScript.js?
Console Error
Just import jquery before you import popup.js
Like this
<!DOCTYPE html>
<html>
<head>
<title>HomAttendance</title>
</head>
<body>
<h1 style="color:#E54E4E">Hom<span style="color:#4E97E5">Attendance</span></h1>
<button type id="record" style="background-color:White"><h1 style="color:Black">Record Attendance</h1></button>
</body>
<script src="jquery-3.4.1.min.js"></script>
<script src="popup.js"></script>
</html>
Inside Your popup.js, when you load markStudents.js which uses jQuery, you'd again have to load jQuery before same
Like this
document.addEventListener('DOMContentLoaded', function () {
var login = document.getElementById('record');
login.addEventListener('click', function () {
chrome.tabs.executeScript(null, { file: "jquery-3.4.1.min.js" }, function () {
chrome.tabs.executeScript(null, { file: "markStudents.js" });
});
});
});
Just reorder your script tags and put jQuery before your popup.js. That way it will be loaded when you try to call it.
yo can use this code to include another jquery file in your jquery:
$.getScript("file address");
like this:
$.getScript("/assets/pages/scripts/ui-blockui.min.js");
i got a ajax procedure that is working ok, but now i need to add a new function to be called just once. so i add this to my current script to get the apex collection clean, but now nothing happens, i placed an alert to verify, but no alert is shown, i guess is because i am placing my clean script in wrong place or there must be something else missing.
// Clean Collection
function()
{
alert('Clean All');
var ajaxRequestd = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=DEL_PRODUCTS",&APP_PAGE_ID.);
ajaxResult = ajaxRequestd.get();
}
here is my full script. thanks for your value tips !!
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Totals</title>
<script type="text/javascript">
$(function()
{
$("#Calculate").click
(
function()
{
// Clean Collection
function()
{
alert('Clean All');
var ajaxRequestd = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=DEL_PRODUCTS",&APP_PAGE_ID.);
ajaxResult = ajaxRequestd.get();
}
$("input[name=f_qty]").each
(
function()
{
var valueInCurrentTextBox = $(this).val();
var productId = $(this).parents('tr').find("input[name=f_prod_id]").val();
$("#P12_PRODUCT_ID").val(productId);
if (valueInCurrentTextBox != '')
{
$("#P12_QTY").val(valueInCurrentTextBox);
var ajaxRequest = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=ADD_PRODUCTS",&APP_PAGE_ID.);
ajaxRequest.add('P12_PRODUCT_ID',html_GetElement('P12_PRODUCT_ID').value);
ajaxRequest.add('P12_QTY',html_GetElement('P12_QTY').value);
ajaxResult = ajaxRequest.get();
}
}
);
alert('Updated!');
}
);
}
);
</script>
</head>
<body>
<div id="totals"></div>
<p align="center" style="clear: both;">
<button type="button" style="font-weight: bold;background-color:lightgray;margin-left:auto;margin-right:auto;display:block;margin-top:0%;margin-bottom:0%" id="Calculate">Add Products</button>
</p>
</body>
</html>
You're declaring that inner function, but never actually calling it. You could assign it to a variable and then call that, but it's actually not needed at all.
Try:
$(function()
{
$("#Calculate").click
(
function()
{
// Clean Collection
alert('Clean All');
var ajaxRequestd = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=DEL_PRODUCTS",&APP_PAGE_ID.);
ajaxResult = ajaxRequestd.get();
$("input[name=f_qty]").each
(
function()
{
var valueInCurrentTextBox = $(this).val();
var productId = $(this).parents('tr').find("input[name=f_prod_id]").val();
$("#P12_PRODUCT_ID").val(productId);
if (valueInCurrentTextBox != '')
{
$("#P12_QTY").val(valueInCurrentTextBox);
var ajaxRequest = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=ADD_PRODUCTS",&APP_PAGE_ID.);
ajaxRequest.add('P12_PRODUCT_ID',html_GetElement('P12_PRODUCT_ID').value);
ajaxRequest.add('P12_QTY',html_GetElement('P12_QTY').value);
ajaxResult = ajaxRequest.get();
}
}
);
alert('Updated!');
});
});