I have 4 mdl tabs where I dynamically create a list of mdl cards in each one. Each card has a mdl-menu created like this:
// job settings dropdown :
settingsButton.setAttribute('id', 'jobSettings');
var jobUl = document.createElement('ul');
jobUl.className = 'mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect';
jobUl.setAttribute('for', 'jobSettings');
var jobLi = document.createElement('li');
var jobLi2 = document.createElement('li');
var jobLi3 = document.createElement('li');
jobLi.className = 'mdl-menu__item';
jobLi2.className = 'mdl-menu__item';
jobLi3.className = 'mdl-menu__item';
jobLi.textContent = 'Edit';
jobLi2.textContent = 'Delete';
jobLi3.textContent = 'Pay';
jobUl.appendChild(jobLi);
jobUl.appendChild(jobLi2);
jobUl.appendChild(jobLi3);
Which would show up in html something like this:
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect"
for="demo-menu-lower-right">
<li class="mdl-menu__item">Edit</li>
<li class="mdl-menu__item">Delete</li>
<li class="mdl-menu__item">Pay</li>
Then I do componentHandler.upgradeDom(); hoping to upgrade the mdl-menu items in each unordered list (ul).
This only seems to work for ONE list element (li) in the entire website. it doesn't work for any other element on any other tab.
How do I make my mdl-menu work on each dynamically created list element in each dynamically created ul?
The issue could be that you are duplicating the id value across multiple menu elements (MDL will get confused if there is more than one button with an id value that matches the for value on your menu element). You could add a numerical increment to your id and for values to ensure that each menu is uniquely identified. See the following example.
const fragment = document.createDocumentFragment();
const addCard = (n) => {
const card = document.createElement('div');
const menu = document.createElement('div');
const button = document.createElement('button');
const icon = document.createElement('i');
const ul = document.createElement('ul');
card.className = 'mdl-card mdl-shadow--2dp';
menu.className = 'mdl-card__menu';
button.id = `menu${n}`;
button.className = 'mdl-button mdl-js-button mdl-button--icon';
icon.className = 'material-icons';
icon.textContent = 'more_vert';
ul.className = 'mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect';
ul.setAttribute('for', `menu${n}`);
fragment.appendChild(card);
card.appendChild(menu);
menu.appendChild(button);
button.appendChild(icon);
menu.appendChild(ul);
for (const action of ['Action 1', 'Action 2', 'Action 3']) {
const li = document.createElement('li');
li.textContent = action;
li.className = 'mdl-menu__item';
ul.appendChild(li);
}
};
for (let i = 0; i < 2; i++) {
addCard(i);
}
document.querySelector('#container').appendChild(fragment);
componentHandler.upgradeDom();
.mdl-card {
margin: 8px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Material Design Lite Cards / Menus</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css">
</head>
<body>
<div id="container"></div>
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
</body>
</html>
Related
I have a todo html element whose inner html i want to save in localstorage through use of html but i am unable to figure out how i would do it.
My javascript code
// Load everything
// get DOM Elements
let to_do_input = document.getElementById("todo-input");
let addBtn = document.getElementById("addBtn");
let display = document.getElementsByClassName("display")[0];
// Event Listeners
addBtn.addEventListener("click", () => {
// Add DOM ELements
let list = document.createElement("ul");
let todos = document.createElement("li");
let deleteBtn = document.createElement("button");
deleteBtn.innerText = "Delete";
// let saveBtn = document.createElement("button");
// saveBtn.innerText = "Save";
display.appendChild(list);
list.appendChild(todos);
list.appendChild(deleteBtn);
// list.append(saveBtn);
// Class names
list.classList.add("list");
todos.classList.add("todos");
deleteBtn.classList.add("deleteBtn");
// saveBtn.classList.add("saveBtn");
// Set values
todos.innerHTML = to_do_input.value;
to_do_input.value = null;
// delete todo
deleteBtn.addEventListener("click", () => {
list.innerHTML = null;
});
// SAVE todo
// saveBtn.addEventListener("click", () => {
// // let arr = [];
// let savedTodo = arr.push(todos.innerHTML);
// localStorage.setItem("todo", JSON.stringify(savedTodo));
// });
// Set saved todo
});
and my html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="This web app provides you with accessibility of todo list" />
<title>Simple To-Do-List</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<h2>A Reliable To-Do-App</h2>
<div class="text-input center">
<input type="text" id="todo-input" placeholder="Write you task here.." />
<button type="button" id="addBtn" )>Add</button>
</div>
<div class="display"></div>
</div>
<script src="app.js"></script>
</body>
</html>
I have reviewed from other sites on how to do it but when i tried the array method , it returned numbers or when i tried to push todos into empty array , it didnt do anything. Also i dont know how i will convert the html element into an object to use it while making todo. Rest all the things work fine.
You need to set a array to save list,
So just edit your JS code to :
// Load everything
// get DOM Elements
let to_do_input = document.getElementById('todo-input')
let addBtn = document.getElementById('addBtn')
let display = document.getElementsByClassName('display')[0]
let todoArray = []
// Event Listeners
addBtn.addEventListener('click', () => {
// Add DOM ELements
let list = document.createElement('ul')
let todos = document.createElement('li')
let deleteBtn = document.createElement('button')
deleteBtn.innerText = 'Delete'
// let saveBtn = document.createElement("button");
// saveBtn.innerText = "Save";
display.appendChild(list)
list.appendChild(todos)
list.appendChild(deleteBtn)
// list.append(saveBtn);
// Class names
list.classList.add('list')
todos.classList.add('todos')
deleteBtn.classList.add('deleteBtn')
// saveBtn.classList.add("saveBtn");
// Set values
todos.innerHTML = to_do_input.value
todoArray.push(to_do_input.value)
to_do_input.value = null
// delete todo
deleteBtn.addEventListener('click', () => {
list.innerHTML = null
})
// SAVE todo
// saveBtn.addEventListener("click", () => {
// // let arr = [];
// let savedTodo = arr.push(todos.innerHTML);
// localStorage.setItem("todo", JSON.stringify(savedTodo));
// });
// Set saved todo
localStorage.setItem('todo', JSON.stringify(todoArray))
})
So been trying to learn more javascript, by doing small projects that are simple but are starting stuff. One of the projects is a to-do app which for some people is really simple, but for me as a starter it's quite complex.
Now here is the thing, I had it working for the most part, I can add stuff, and one thing only HALF works, I wrote a bit that adds a X button to a li element. Now it works when I put the li element in the HTML page itself, but when it's added through javascript, it doesn't.
There is no error, it was working before but for some reason it.. broke.
<!DOCTYPE html>
<head>
<title>To Do App!</title>
<link rel="stylesheet" type="text/css" href="CSS/stylesheet.css">
</head>
<body>
<div id="h1Div">
<h1> To-do app! </h1>
<input type="text" id="inputForList">
<input type="button" id="btnInput" value="Add me!" onclick="btnFunction()">
</div>
<ul id="ulSection">
<li>Test 1</li>
<li>Test 2</li>
</ul>
<script src="Scripts/javascript.js"></script>
</body>
This is the HTML page, super simple.
//Adds li element with input from a textbox
function btnFunction(){
var cLi = document.createElement("li");
var inpList = document.getElementById("inputForList").value;
var txtNode = document.createTextNode(inpList);
cLi.appendChild(txtNode);
//Check to see if anything is filled in, otherwise send message. And 'appends' it to the list item
if(inpList === ''){
alert("Voeg wat toe!");
} else {
document.getElementById("ulSection").appendChild(cLi);
}
// Reset value of Textbox to ""
document.getElementById("inputForList").value = "";
}
//Sets a 'x' on every element.
var ulList = document.getElementsByTagName("li");
var i;
for(i = 0; i < ulList.length; i++){
var span = document.createElement("span");
var xBtn = document.createTextNode("\u00D7");
span.className = "Done";
span.appendChild(xBtn);
ulList[i].appendChild(span);
}
And this is the Javascript.
As stated, it worked before. But for some reason, now the bottom section, the X button (\u00D7) part, it sn't working on the 'new stuff' that I add through the text input..
Your code is good, you just need to do the same thing you did in
var ulList = document.getElementsByTagName("li");
var i;
for (i = 0; i < ulList.length; i++) {
var span = document.createElement("span");
var xBtn = document.createTextNode("\u00D7");
span.className = "Done";
span.appendChild(xBtn);
ulList[i].appendChild(span);
}
in btnFunction() (with the exception of the for loop, which isn't needed in the function, as only one element is added at a time). The reason for this is your code only runs when the page is loaded, or when it is specifically told to run (in your case, on a button click). if you just create an element the js doesn't know to update it with an x, you have to tell it to do so.
//Adds li element with input from a textbox
function btnFunction() {
var cLi = document.createElement("li");
var inpList = document.getElementById("inputForList").value;
var txtNode = document.createTextNode(inpList);
cLi.appendChild(txtNode);
//Check to see if anything is filled in, otherwise send message. And 'appends' it to the list item
if (inpList === '') {
alert("Voeg wat toe!");
} else {
document.getElementById("ulSection").appendChild(cLi);
var ulList = document.getElementsByTagName("li");
var span = document.createElement("span");
var xBtn = document.createTextNode("\u00D7");
span.className = "Done";
span.appendChild(xBtn);
ulList[ulList.length-1].appendChild(span);
}
// Reset value of Textbox to ""
document.getElementById("inputForList").value = "";
}
//Sets a 'x' on every element.
var ulList = document.getElementsByTagName("li");
var i;
for (i = 0; i < ulList.length; i++) {
var span = document.createElement("span");
var xBtn = document.createTextNode("\u00D7");
span.className = "Done";
span.appendChild(xBtn);
ulList[i].appendChild(span);
}
<!DOCTYPE html>
<head>
<title>To Do App!</title>
<link rel="stylesheet" type="text/css" href="CSS/stylesheet.css">
</head>
<body>
<div id="h1Div">
<h1> To-do app! </h1>
<input type="text" id="inputForList">
<input type="button" id="btnInput" value="Add me!" onclick="btnFunction()">
</div>
<ul id="ulSection">
<li>Test 1</li>
<li>Test 2</li>
</ul>
<script src="Scripts/javascript.js"></script>
</body>
Super new to all of this so this might be some beginner troubleshooting. The list seems to be working where I'm adding a list element to the UL with a checkbox and delete button. When checkbox is checked it puts a line through the text and when the delete button is clicked it deletes the list element. The assignment asks to save to localStorage so that when refreshed, the list items still remain, and I'm getting super confused by this. What I have now seems to be saving my list elements to an array but I don't understand how to get them to save and stay on the page.
const form = document.querySelector('form');
const input = document.querySelector('#todoInput');
const newElement = document.querySelector('ul');
const savedToDos = JSON.parse(localStorage.getItem('todos')) || [];
newElement.addEventListener('click', function(e) {
if(e.target.tagName === 'BUTTON') {
e.target.parentElement.remove()
}
})
function addToList(text) {
const li = document.createElement('li');
const checkbox = document.createElement('input');
const button = document.createElement('button');
button.innerText = "Delete";
checkbox.type = 'checkbox';
checkbox.addEventListener('change', function() {
li.style.textDecoration = checkbox.checked ? 'line-through' : 'none';
})
li.innerText = text;
li.insertBefore(checkbox, li.firstChild);
li.appendChild(button);
return li;
};
form.addEventListener('submit', function(e) {
e.preventDefault();
const newListItem = addToList(input.value);
input.value = '';
newElement.append(newListItem);
savedToDos.push(newListItem.innerText);
localStorage.setItem('todos', JSON.stringify(savedToDos));
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToDo App</title>
<link rel="stylesheet" href="app.css">
</head>
<body>
<div>
<h1>Todo List</h1>
<form action="">
<input type="text" id="todoInput" placeholder="Add To Todo List">
<button class="add-button">Add</button>
</form>
<ul id="todoList">
</ul>
</div>
<script src="app.js"></script>
</body>
</html>
It looks like you're failing to populate the DOM when the page loads.
After you retrieve the items from local storage (which you're already doing), loop through the list and add each of them to the DOM:
// After this line, which you've already written:
const savedToDos = JSON.parse(localStorage.getItem('todos')) || [];
// Loop through savedToDos, and for each one, insert a new list:
savedToDos.forEach(function(value) {
const newListItem = addToList(value);
newElement.append(newListItem);
});
Every browser has local storage where we can store data and cookies. just go to the developer tools by pressing F12, then go to the Application tab. In the Storage section expand Local Storage.
this piece of code might help you
// Store Task
function storeTaskInLocalStorage(task) {
let tasks;
if(localStorage.getItem('tasks') === null){
tasks = [];
} else {
tasks = JSON.parse(localStorage.getItem('tasks'));
}
tasks.push(task);
localStorage.setItem('tasks', JSON.stringify(tasks));
}
I'm creating a to-do list for class:
Lab 4: Todo List Let's make a simple todo-list which supports the
following operations: add an item to the list remove an item from the
list mark an item as completed Removed items should disappear
entirely. Completed items should appear at the bottom (or in a
separate list) with a line through them.
I'm unable to remove multiple li from my ul. I get an error after removing the first.
lab-04.js:16 Uncaught DOMException: Failed to execute 'removeChild' on
'Node': The node to be removed is not a child of this node. at
HTMLButtonElement.removeBtn.onclick
(http://127.0.0.1:5500/js/lab-04/lab-04.js:16:18)
Oddly, enough the buttons are removed without much fuss.
The code (js):
let manipulateDom = () => {
let container = document.getElementsByClassName('container')
let toDoList = document.getElementById('to-do')
let removeBtn = document.createElement('button')
content = document.getElementById('userInput').value
listItem = document.createElement('li')
listItem.className = 'list-item'
listItem.textContent = (content)
removeBtn.appendChild(document.createTextNode('remove'))
removeBtn.onclick = function() {
toDoList.removeChild(removeBtn)
toDoList.removeChild(listItem)
}
toDoList.appendChild(listItem)
toDoList.appendChild(removeBtn)
}
(html):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>lab-04</title>
<script src='/js/lab-04/lab-04.js'></script>
</head>
<body>
<h4>To Do List</h4>
<input type='text' id='userInput' placeholder="item to add">
<input type="submit" onclick="manipulateDom()">
<ul id='to-do'>
</ul>
<ul id='done'>
</ul>
</body>
</html>
Any help is greatly appreciated, ready to pull my hair out
You are putting your listItem in the window scope, and what removeBtn.onclick does is removing the listItem in the window scope, that's why the remove button only works once and only works on the last element created.
Declare listItem in the block scope and it should be working again
let manipulateDom = () => {
let container = document.getElementsByClassName('container');
let toDoList = document.getElementById('to-do');
let removeBtn = document.createElement('button');
let content = document.getElementById('userInput').value;
let listItem = document.createElement('li');
listItem.className = 'list-item';
listItem.textContent = (content);
removeBtn.appendChild(document.createTextNode('remove'))
removeBtn.onclick = function() {
toDoList.removeChild(removeBtn);
toDoList.removeChild(listItem);
};
toDoList.appendChild(listItem);
toDoList.appendChild(removeBtn);
}
<h4>To Do List</h4>
<input type='text' id='userInput' placeholder="item to add">
<input type="submit" onclick="manipulateDom()">
<ul id='to-do'>
</ul>
<ul id='done'>
</ul>
I'm trying to dynamically set the content of a popup.
Here is a first HTML page where everything is defined statically :
<html>
<head>
<meta charset='utf-8'>
<link href='css/font-awesome.css' rel='stylesheet'>
<link href='css/myStyle.css' rel='stylesheet'>
</head>
<body>
<div id="data">
<ul class='links-list'>
<li><a target='_blank' href='siteURL'><i class='myButton'>TEXT</i></a></li>
<li><a target='_blank' href='twitterURL'><i class='myButton'>TEXT</i></a></li>
</ul>
</div>
</body>
</html>
Now I need to dynamically set my buttons, so I've removed everything which will be dynamically created :
<html>
<head>
<meta charset='utf-8'>
<link href='css/font-awesome.css' rel='stylesheet'>
<link href='css/myStyle.css' rel='stylesheet'>
</head>
<body>
<div id="data">
</div>
<script type="text/javascript" src="script.js">
</script>
</body>
</html>
My content script "script.js" receive data (array of links) and have to create buttons in my HTML document :
self.port.on("liste", function(list)
{
var div = document.getElementById('data'); // Get <div id="data">
var ul = document.createElement('ul'); // Create <ul class='links-list'>
ul.class = 'links-list';
for (var i = 0; i < list.links.length; ++i)
{
var site = list.links[i];
var li = document.createElement('li'); // Create <li>
var link = document.createElement('a'); // Create <a>
var button = document.createElement('i'); // Create <i>
button.class = "myButton";
link.text = site.text;
link.href = site.url;
link.target = '_blank';
link.appendChild(button);
li.appendChild(link);
ul.appendChild(li);
}
div.appendChild(ul);
});
Issue is links created dynamically aren't using "myStyle.css", here is a comparaison :
Static vs dynamic load :
Could anyone help me resolving this? Thank you.
The correct way to give an item a class using javascript is - unintuitively enough - className, or setAttribute. So either of these will add the correct class:
button.className = 'myButton'
button.setAttribute('class', 'myButton')
Using just .class does not work in Javascript:
document.getElementById('a1').class = 'aClass';
document.getElementById('a2').className = 'aClass';
document.getElementById('a3').setAttribute('class', 'aClass');
.aClass { color: red; }
<pre id="a1">.class</pre>
<pre id="a2">.className</pre>
<pre id="a3">.setAttribute</pre>
Looks to me like the comment from CBroe is the answer. In your javascript you're putting the text into the link instead of your button. That means that the button will essentially be invisible. That's why it looks different from your hard-coded example. Try this javascript instead.
var div = document.getElementById('data'); // Get <div id="data">
var ul = document.createElement('ul'); // Create <ul class='links-list'>
ul.className = 'links-list';
for (var i = 0; i < 4; ++i){
var url = i;
var li = document.createElement('li'); // Create <li>
var link = document.createElement('a'); // Create <a>
var button = document.createElement('i'); // Create <i>
button.className = "myButton";
button.innerHTML = 'text'+i;
link.text = "ab ";
link.href = url;
link.target = '_blank';
link.appendChild(button);
li.appendChild(link);
ul.appendChild(li);
}
div.appendChild(ul);