My JavaScript code isn't working properly in Mozilla Firefox - javascript

I have a to-do list application on my website that I built using JavaScript. It works perfectly in Google Chrome, but it doesn't work in Mozilla Firefox. I have read that each browser interprets JavaScript differently, but I haven't been able to pinpoint exactly what the problem is in the code.
So, what happens in Firefox is this: When you type something into the text input and click the "Add Task" button, it does show that a task has been added. However, the label appears blank, as do the Edit and Delete buttons. All of the functionality appears to work as normal (the Edit and Delete buttons work properly, they just don't display the text).
In the code, the each list item is created by a function called createTask. Its code is:
var createTask = function(taskString) {
// taskString is the value of the text input (whatever the user wants the task to read)
// Create Elements
var listItem = document.createElement("li");
var checkbox = document.createElement("input");
var label = document.createElement("label");
var editInput = document.createElement("input");
var editButton = document.createElement("button");
var deleteButton = document.createElement("button");
// Modify Elements
checkbox.type = "checkbox";
label.innerText = taskString;
editInput.type = "text";
editButton.innerText = "Edit";
deleteButton.innerText = "Delete";
// Add Event Listeners
checkbox.addEventListener("change", markTask);
editButton.addEventListener("click", editTask);
deleteButton.addEventListener("click", deleteTask);
// Append the Elements to the List Item
listItem.appendChild(checkbox);
listItem.appendChild(label);
listItem.appendChild(editInput);
listItem.appendChild(deleteButton);
listItem.appendChild(editButton);
return listItem;
}
Then, the function addTask appends listItem to the unordered list that is the tasks list.
var addTask = function() {
if (addInput.value === "") {
addError.style.display = "block"; // Display error message if no input
} else {
addError.style.display = "none"; // Stop displaying error message
var listItem = createTask(addInput.value); // Put user input into createTask function
tasksList.appendChild(listItem); // Add the new list item to the unordered list
addInput.value = ""; // Reset the text input field to blank
addInput.focus();
}
}
Looking more closely, within the createTask function, there is:
label.innerText = taskString;
editButton.innerText = "Edit";
deleteButton.innerText = "Delete";
So, I thought that the innerText property may not work properly in Firefox, but I tried changing it to innerHTML and textContent, and that doesn't work either!
Any ideas?

innerText is deprecated.
Try using textContent instead.
This issue has been described here:
'innerText' works in IE, but not in Firefox

use .textContent and log listItem in console you will see they are constructed properly.below is your code with small changes.tested in firefox:
var createTask = function(taskString) {
// taskString is the value of the text input (whatever the user wants the task to read)
// Create Elements
var listItem = document.createElement("li");
var checkbox = document.createElement("input");
var label = document.createElement("label");
var editInput = document.createElement("input");
var editButton = document.createElement("button");
var deleteButton = document.createElement("button");
// Modify Elements
checkbox.type = "checkbox";
label.textContent = taskString;
editInput.type = "text";
editButton.textContent = "Edit";
deleteButton.textContent = "Delete";
//alert(deleteButton.textContent);
// Add Event Listeners
// checkbox.addEventListener("change", markTask); // commented these because i do not had these objects.
// editButton.addEventListener("click", editTask);
// deleteButton.addEventListener("click", deleteTask);
// Append the Elements to the List Item
listItem.appendChild(checkbox);
listItem.appendChild(label);
listItem.appendChild(editInput);
listItem.appendChild(deleteButton);
listItem.appendChild(editButton);
console.log(listItem);
return listItem;
}

Related

document.getElementById(idz.toString()) causing Type Error: typ1 is null javascript

I am trying to add a check box when button is pressed and also delete the same checkbox when the delete is pressed. Unfortunatly the delete function cannot run as it seems that the newly created div doesn't exist yet. How can I get around this?
<script>
const list = document.getElementById("list");
const cli_form = document.getElementById("client-form");
let idz = 0;
function add_client(input) {
const div = document.createElement("div");
div.setAttribute("id", idz.toString())
const newCheckbox = document.createElement("input");
newCheckbox.setAttribute("type", 'checkbox');
newCheckbox.setAttribute("id", 'checkbox');
const newLabel = document.createElement("label");
newLabel.setAttribute("for", 'checkbox');
newLabel.innerHTML = input.value;
const br = document.createElement("br");
const del = document.createElement("input");
del.setAttribute("type", 'button');
del.setAttribute("value", idz.toString());
del.onclick = delete_item(document.getElementById(idz.toString()));
div.appendChild(newCheckbox);
div.appendChild(newLabel);
div.appendChild(del);
div.appendChild(br);
list.appendChild(div);
idz++;
}
function delete_item(item1) {
item1.remove();
}
</script>
You are assigning the result of the function delete_item which invoke immediately. Therefore, it is removing the item before it is being added to DOM.
You might use an arrow wrapper to avoid immediate invocation.
Like this :
del.onclick = () => delete_item(document.getElementById(idz.toString()));

How to create an object of an <li> element?

I created a To-Do List with JS. I'm mostly finished but my last task is to create a local storage. The purpose of that is, that the Tasks should not vanish, when I reload the page. I know that I have to create an array of objects for that, but I don't know how to represent my <'li'> element as an object. So how do I represent my Tasks as an object to create an array
add.addEventListener("click", function (){
// create task text
if(task.value != ""){
let li = document.createElement('li');
ul.appendChild(li);
// create checkbox
let box = document.createElement('input');
box.setAttribute('type', 'checkbox');
li.appendChild(box);
box.classList.add('check');
//create span
let span = document.createElement('span');
li.appendChild(span);
span.innerHTML= task.value;
span.classList.add('task');
// create delete button
let btn = document.createElement('button');
li.appendChild(btn);
btn.classList.add("delete-btn");
btn.innerHTML = 'x';
btn.onclick = function () {
btn.parentElement.remove();
};
});

Moving a Checked Li to the Bottom of a UL

I am making a todo list, i have just about everything for it figured out but one area i am stuck on is my UL and Li.
Basically when you enter items into the list, you have the ability to click the checkbox beside said item when you complete the task, and it will put a line through the text.
But i also want it to move that item to the bottom of the list when it is clicked.
would anyone be able to help me with how i would go about doing that
code Below
// making event listener for adding item
let addBTN = document.getElementById('addBtn');
addBTN.addEventListener('click', addItem);
// this creates a new li based on the entered value in the text box that it gets when you hit the button
// Through Research found that setAttribute isn't really needed and i can just use .id , .type etc
function addItem() {
// Creating needed elements as well as getting text from textbox
let newLi = document.createElement("li");
let myLiValue = document.getElementById('textBoxAdd').value;
let liTextNode = document.createElement("label");
liTextNode.textContent = myLiValue;
// makes div for li
let newDivID = ('div_' + myLiValue);
let newDiv = document.createElement('div');
newDiv.id = newDivID;
// makes checkboxes for the li
let newCheckBoxID = ('checkbox_' + myLiValue);
let newCheckBox = document.createElement('input');
newCheckBox.type = 'checkbox';
newCheckBox.id = newCheckBoxID;
// makes delete button for the li
let newDeleteID = ('deleteButton_' + myLiValue);
let newDeleteButton = document.createElement("button")
newDeleteButton.type = 'button';
newDeleteButton.id = newDeleteID
newDeleteButton.textContent = 'Delete';
//newDeleteButton.setAttribute('onclick', 'deleteItem()');
newDeleteButton.innerHTML = 'Delete';
// appends it to my newDiv
newDiv.appendChild(newCheckBox);
newDiv.appendChild(liTextNode);
newDiv.appendChild(newDeleteButton);
// then appends my new div to the new Li
newLi.appendChild(newDiv);
// this just makes sure a user cant enter in a blank value
if (myLiValue == "") {
alert("Please Enter Something Before Hitting Add Item");
} else {
document.getElementById('theNewList').appendChild(newLi);
document.getElementById('textBoxAdd').value = "";
}
}
//creating event listener for checkbox line through text and moving item
let theList = document.getElementById('theNewList');
theList.addEventListener('click', checkedComplete);
// function that will target every check box in the list and if any get checked then it will add a line through the text
function checkedComplete(event) {
const checkboxElement = event.target;
if (checkboxElement.type === 'checkbox') {
if (checkboxElement.checked) {
checkboxElement.nextElementSibling.style.textDecoration = 'line-through';
// add in moving item
} else {
checkboxElement.nextElementSibling.style.textDecoration = 'none';
}
}
}
// adds deleteItem listener to the list
theList.addEventListener('click', deleteItem);
function deleteItem(event) {
const deleteButton = event.target;
if (deleteButton.type === 'button') {
const deleteParentNode = deleteButton.parentNode;
deleteParentNode.parentNode.removeChild(deleteParentNode);
}
}
You are going to have a storage of you todos, right? Even if you did not think about it, it can do all the work. Just create the array (you could use localStorage to prevent you data from disappearing after browser is restarted) containing your todos and their condition, like
const todos = [{todo:"watch the movie", completed: false}, {...}, {...}]
Now you can easily add or remove items with standard array methods pop&push, delete with splice, filter etc. After array is mdified, just update the page and build your list using Array.map.
You should just add the following logic where you have // add in moving item comment:
const theList = document.getElementById('theNewList');
const lastListItem = theList.children[theList.children.length - 1];
theList.insertBefore(lastListItem, checkboxElement.parentNode.parentNode);
We're selecting your ul and searching for its last li and then we're simply placing the li belonging to the checkboxElement after the last li.
Working example:
// making event listener for adding item
let addBTN = document.getElementById('addBtn');
addBTN.addEventListener('click', addItem);
// this creates a new li based on the entered value in the text box that it gets when you hit the button
// Through Research found that setAttribute isn't really needed and i can just use .id , .type etc
function addItem() {
// Creating needed elements as well as getting text from textbox
let newLi = document.createElement("li");
let myLiValue = document.getElementById('textBoxAdd').value;
let liTextNode = document.createElement("label");
liTextNode.textContent = myLiValue;
// makes div for li
let newDivID = ('div_' + myLiValue);
let newDiv = document.createElement('div');
newDiv.id = newDivID;
// makes checkboxes for the li
let newCheckBoxID = ('checkbox_' + myLiValue);
let newCheckBox = document.createElement('input');
newCheckBox.type = 'checkbox';
newCheckBox.id = newCheckBoxID;
// makes delete button for the li
let newDeleteID = ('deleteButton_' + myLiValue);
let newDeleteButton = document.createElement("button")
newDeleteButton.type = 'button';
newDeleteButton.id = newDeleteID
newDeleteButton.textContent = 'Delete';
//newDeleteButton.setAttribute('onclick', 'deleteItem()');
newDeleteButton.innerHTML = 'Delete';
// appends it to my newDiv
newDiv.appendChild(newCheckBox);
newDiv.appendChild(liTextNode);
newDiv.appendChild(newDeleteButton);
// then appends my new div to the new Li
newLi.appendChild(newDiv);
// this just makes sure a user cant enter in a blank value
if (myLiValue == "") {
alert("Please Enter Something Before Hitting Add Item");
} else {
document.getElementById('theNewList').appendChild(newLi);
document.getElementById('textBoxAdd').value = "";
}
}
//creating event listener for checkbox line through text and moving item
let theList = document.getElementById('theNewList');
theList.addEventListener('click', checkedComplete);
// function that will target every check box in the list and if any get checked then it will add a line through the text
function checkedComplete(event) {
const checkboxElement = event.target;
if (checkboxElement.type === 'checkbox') {
if (checkboxElement.checked) {
checkboxElement.nextElementSibling.style.textDecoration = 'line-through';
const theList = document.getElementById('theNewList');
const lastListItem = theList.children[theList.children.length - 1];
theList.insertBefore(checkboxElement.parentNode.parentNode, lastListItem.nextSilbing);
} else {
checkboxElement.nextElementSibling.style.textDecoration = 'none';
}
}
}
// adds deleteItem listener to the list
theList.addEventListener('click', deleteItem);
function deleteItem(event) {
const deleteButton = event.target;
if (deleteButton.type === 'button') {
const deleteParentNode = deleteButton.parentNode;
deleteParentNode.parentNode.removeChild(deleteParentNode);
}
}
<input id="textBoxAdd" type="text" />
<button id="addBtn" type="button">Add</button>
<ul id="theNewList"></ul>

Unable to get asynchronous child spawning in JavaScript

I'm trying to format this code in such a way that when a user clicks a button, new input fields each with a redirect button gets inserted asynchronously into the un-ordered list, it worked up until i added the redirect button to also be inserted upon each click of the spawn button.
Here is my JS code...
function spawnSilly()
{
var div = document.createElement("DIV");
var input = document.createElement("INPUT");
var button = document.createElement("BUTTON");
var att1 = document.createAttribute("type")
var att2 = document.createAttribute("placeholder")
var att3 = document.createAttribute("type")
var att4 = document.createAttribute("onClick")
att1.value = "text"
att2.value = "Title"
att3.value = "button"
att4.value = "redirect()"
input.setAttributeNode(att1)
input.setAttributeNode(att2)
button.setAttribute(att3)
button.setAttribute(att4)
div.appendChild(input)
div.appendChild(button);
var list = document.getElementById("spawnList");
list.insertBefore(div, list.childNodes[0]);
}
This is my HTML
<ul id="spawnList">
</ul>
<button id="spawnbtn" onClick="spawnSilly()">Add</button>
Seems to be the button thats causing the issue, but i can't figure out why?
Any help would be awesome! thanks
Note that setAttribute() takes two arguments, the name of the attribute and the value. Using this in the right way, the code can be simplified like this:
function redirect()
{
console.log("Redirect clicked!");
}
function spawnSilly()
{
var div = document.createElement("DIV");
var input = document.createElement("INPUT");
var button = document.createElement("BUTTON");
input.setAttribute("type", "text");
input.setAttribute("placeholder", "Title");
button.setAttribute("type", "button");
button.setAttribute("onClick", "redirect()");
button.innerHTML = "Redirect";
div.appendChild(input)
div.appendChild(button);
var list = document.getElementById("spawnList");
list.insertBefore(div, list.childNodes[0]);
}
.as-console {background-color:black !important; color:lime;}
<ul id="spawnList"></ul>
<button id="spawnbtn" onClick="spawnSilly()">Add</button>
setAttribute take two parameters, first is the name of attribute and second is value, but you have only one - https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute.
Instead you can set the value to attributes using . operator.
Also, you are attaching a function call att4.value = "redirect()". So, whenever the button gets added your redirect will get called. Instead attach a callback to redirect, so it gets called when the button is clicked.
function spawnSilly()
{
const div = document.createElement("DIV");
const input = document.createElement("INPUT");
const button = document.createElement("BUTTON");
input.type = "text";
input.value = "Title";
button.type ="button";
button.onclick = redirect;
button.textContent = "Click Me!";
div.appendChild(input)
div.appendChild(button);
const list = document.getElementById("spawnList");
list.insertBefore(div, list.childNodes[0]);
}
function redirect() {
console.log('In redirect');
}
<ul id="spawnList">
</ul>
<button id="spawnbtn" onClick="spawnSilly()">Add</button>

adding an onchange event to select

I have the following js code:
function createConBox() {
var charDiv = document.getElementById("characterList"); // reference to "characterList" div
header = document.createElement("p"); // creates the <p> tag
charDiv.appendChild(header); // adds the <p> tag to the parent node
title = document.createTextNode("Show Only Lines By:"); // creates the text string
header.appendChild(title); // adds the text string to the parent node
// create select box and add elements
selectBox = document.createElement("select");
selectBox.setAttribute("id", "cList");
charDiv.appendChild(selectBox);
charNames = uniqueElemText("h3"); // array of character names
newOption = document.createElement("option");
selectBox.appendChild(newOption);
newOptionTitle = document.createTextNode("Show All Lines");
newOption.appendChild(newOptionTitle);
for (i = 0; i < charNames.length; i++) {
newOption = document.createElement("option");
selectBox.appendChild(newOption);
newOptionTitle = document.createTextNode(charNames[i]);
newOption.appendChild(newOptionTitle);
}
}
function showLines() {
alert("The Box has been changed");
}
Every time the option in the box is changed, I want it to call 'showLines()'. However, every time I try to implement an event, I can only get it to trigger when the page loads, and never again thereafter.
selectBox.onchange = showLines; should solve your problem.
in some browsers onchange get fired only after blurring select box. to over come this you can use onclick instead of onchange
My guess is that you're doing this:
selectBox.onchange = showLines();
If that's the case, just remove the ():
selectBox.onchange = showLines;
When I pass dynamically id in case then what I do:
var selectcell = tablerow.insertCell(1);
var selectelmt = document.createElement('select');
selectelmt.name = 'Select';
selectelmt.value = 'select';
selectelmt.classList = 'form-control input-sm cobclass';
selectelmt.onchange= onselectchange(i);
selectelmt.id = 'cobselect' + i;
selectelmt.options[0] = new Option('select');
selectcell.appendChild(selectelmt);
// ddrbind(i);
show();
i++;`

Categories