Can someone validate this JavaScript code (to do list) - javascript

Here's the code...
https://jsfiddle.net/6n2k65zs/
Try add a new item, you'll see its not working for some reason but it should be...
I can't spot any errors in the code, can someone help me out please?
And does anyone know any good debuggers? debugging JS is a nightmare!
Thanks.
<!DOCTYPE html>
<html>
<head>
<title>JavaScript To-Do List</title>
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<input id="input" type="text">
<button id="btn">Add</button>
<hr>
<ul id="todo">
</ul>
<ul id="done">
</ul>
<!-- javascript anonymous self-invoking function -->
<!-- Function expressions will execute automatically -->
<script>
// from outside the action you wont be able to access the variables
// prevents another variable with a same name from conflicting
(function(){
var input = document.getElementById('input');
var btn = document.getElementById('btn');
// Object for the lists
// the reason im using ID is because ID can only be named once rather than a class which can be named 100's of times
var lists = {
todo:document.getElementById('todo'),
done:document.getElementById('done')
};
/* Parameter is string
create a list element which is stored in 'el' and returns it
*/
var makeTaskHtml = function(str, onCheck) {
var el = document.createElement('li');
var checkbox = document.createElement('input');
var label = document.createElement('span');
label.textContent = str;
checkbox.type = 'checkbox';
checkbox.addEventListener('click', onCheck);
// el.textContent = str;
// can use this method to move an element from one element to another
el.appendChild(checkbox);
el.appendChild(label);
// Text content is grabbing the text from the text box and storing it in variable el.
return el;
};
var addTask = function(task) {
lists.todo.appendChild(task);
};
var onCheck = function(event){
var task = event.target.parentElement; //targets the item clicked
var list = task.parentElement.id;
//lists.done.appendChild(task);
//swaps the 2 objects around
lists[list === 'done' ? 'todo' : 'done'].appendChild(task);
this.checked = false;
input.focus();
};
var onInput = function() {
var str = input.value.trim; // trim removes white space...
if (str.length > 0) {
addTask(makeTaskHtml(str, onCheck));
input.value = '';
input.focus();
}
};
btn.addEventListener('click', onInput);
input.addEventListener('keyup', function(event){
var code = event.keyCode;
console.log(code);
if (code === 13) {
onInput();
}
});
input.focus();
addTask(lists.todo, makeTaskHtml('Test done', onCheck));
}());
</script>
</body>
</html>

It appears to me you are not calling trim as a method, but accessing it as a variable?
Try add the () in trim:
var onInput = function() {
var str = input.value.trim(); // trim removes white space...

Your addTask function is being called with 3 parameters:
addTask(lists.todo, makeTaskHtml('Test done', onCheck));
but the function definition for addTask only takes one parameter:
var addTask = function(task)
so you need to just call addTask with just makeTaskHtml parameter, and not lists.todo which is already referenced inside the addTask function or onCheck

Or for debugging in Chrome, try Cmd-Alt–I in (Mac) or Ctrl-Alt-I (Windows).
First of all, you shouldn't put your scripts inline in JSFiddle – put them in the JS box to protect everyone's sanity! It's what it's made for...
There are other issues in the code, but the main issue seems to be in this line:
var str = input.value.trim;
Here, you're assigning str to the JS function trim. You want to assign it the the results of trim(), so try:
var str = input.value.trim();
You're still getting other errors in the console, but the basics seem to work.

Related

How can I clear a "innerHTML" with Javascript?

I have this HTML:
<div id = "options"></div>
I access to this div trough this Javascript:
var test = "hola";
document.getElementById('options').innerHTML=
<p>Test</p> <li>${test}</li>
And I have this button:
function click({
document.getElementById("Click").addEventListener("click", function(){
});
};
click();
I need that when that function called "click" is executed automatically that <li> can clean that value of the variable: "test" and it is seen empty.
How can I do it? Thank you
el.innerHTML is the property which keeps track of HTML text values shown inside the element. You can set that to empty whenever you want to clear it.
Try this sample - https://jsitor.com/J0gXikZmV
<div id = "options"></div>
var test = "hola";
let el = document.getElementById("options");
el.innerHTML = "<p>Test</p> <li>${test}</li>";
el.addEventListener('click', () => {
el.innerHTML = '';
})
Here it clear the html content of div

javascript dynamically remove text

I have successfully created a button which adds text to the webpage however I do not know a viable way to remove text once this has been created. The js code I have is:
var addButtons = document.querySelectorAll('.add button');
function addText () {
var self = this;
var weekParent = self.parentNode.parentNode;
var textarea = self.parentNode.querySelector('textarea');
var value = textarea.value;
var item = document.createElement("p");
var text = document.createTextNode(value);
item.appendChild(text)
weekParent.appendChild(item);
}
function removeText() {
//document.getElementbyId(-).removeChild(-);
}
for (i = 0; i < addButtons.length; i++) {
var self = addButtons[i];
self.addEventListener("click", addText);
}
I have viewed various sources of help online including from this site however I simply cannot get any to work correctly. Thank you in advance.
Sure, it should be easy to locate the added <p> tag relative to the remove button that gets clicked.
function removeText() {
var weekParent = this.parentNode.parentNode;
var item = weekParent.querySelector("p");
weekParent.removeChild(item);
}
If there is more than 1 <p> tag inside the weekParent you will need a more specific querySelector.

Struggling to keep HTML and JS separate

I'm creating a basic to do list in Vanilla JS, I'm using Handlebars to keep the HTML & JS separate.
Everything was going fine till I came to the delete method. Because my delete button is inside my HTML and not created inside my JS I'm finding it hard to select and delete items from the array.
I thought I'd found a way around it by looping over them but the issue with this is it tries to grab the buttons on page load, and so it returns always an empty array as on page load there are no delete buttons as no to do has been added at that point.
I've also tried putting the delete method inside the add method to counter this but this also presented issues.
Simply, can someone give me an example of a working delete method that removes the relevant item from the array using splice.
Cheers
HTML
<input id="add-to-do-value" type="text" placeholder="Add to do">
<button id="add-to-do">Add</button>
<div id="to-do-app"></div>
<script type="text/javascript" src="js/handlebars.js"></script>
<script id="to-do-template" type="text/template">
<ul>
{{#this}}
<div>
<li id={{id}}>
{{value}}
<button class="delete-btn" id={{id}}>Delete</button>
</li>
</div>
{{/this}}
</ul>
</script>
<script type="text/javascript" src="js/app.js"></script>
JS
(function() {
// Data array to store to dos
var data = [];
// Cache dom
var toDoApp = document.getElementById('to-do-app');
var toDoTemplate = document.getElementById('to-do-template');
var addToDo = document.getElementById('add-to-do');
var addToDoValue = document.getElementById('add-to-do-value');
var toDoTemplate = Handlebars.compile(toDoTemplate.innerHTML);
// Render HTML
var render = function() {
toDoApp.innerHTML = toDoTemplate(data);
}
// Add to dos
var add = function() {
var toDoValue = addToDoValue.value;
if(toDoValue) {
var toDoObj = {
value: toDoValue,
id: Date.now(),
}
data.push(toDoObj);
}
render();
}
// Delete to dos
var deleteBtn = document.querySelectorAll('.delete-btn');
for(i=0; i<deleteBtn.length; i++) {
deleteBtn[i].addEventListener("click", function(){
for(j=0; j<data.length; j++) {
if(data[j].id == this.id) {
data.splice(data[j], 1);
render();
}
}
});
}
// Bind events
addToDo.addEventListener("click", add);
})();
The fact that you're using Handlebars makes the whole thing unnecessary complex. I would suggest that you don't use innerHTML, but other parts of the DOM API instead to be able to easily access the elements you need. For more complex todo items, I would consider using <template>s.
Anyway, you have to bind the event listener for removing the item when you create the new item (i.e. in the add function):
var todos = [];
var input = document.querySelector('input');
var addButton = document.querySelector('button');
var container = document.querySelector('ul');
var add = function () {
var content = input.value;
input.value = '';
var id = Date.now();
var li = document.createElement('li');
li.appendChild(document.createTextNode(content));
var button = document.createElement('button');
button.textContent = 'Delete';
button.addEventListener('click', remove.bind(null, id));
li.appendChild(button);
todos.push({ content, id, element: li });
container.appendChild(li);
};
var remove = function (id) {
var todo = todos.find(todo => todo.id === id);
container.removeChild(todo.element);
todos = todos.filter(t => t !== todo);
};
addButton.addEventListener('click', add);
<input type="text" placeholder="Add to do">
<button>Add</button>
<ul></ul>

Adding a list item

Could anyone please help me sort out a bug in my beginner code? I am trying to add an list item to a list and trying to change the id of what list i'm adding it to in javascript. Thanks in advance.
<html>
<head>
<script>
window.onload = init;
function init() {
var button = document.getElementById("submit");
button.onclick = changeDiv;
}
function changeDiv() {
var counter=1
var name = "ul";
var textInput = document.getElementById("textInput");
var userInput = textInput.value;
alert("adding " + userInput);
var li = document.createElement("li");
li.innerHTML = userInput;
var ul = document.getElementById("ul" + loop());
ul.appendChild(li);
}
function loop() {
return counter;
if (counter==3){
counter==0;
}
counter++;
}
</script>
</head>
<body>
<form id="form">
<input id="textInput" type="text" placeholder="input text here">
<input id="submit" type="button">
</form>
<ul id="ul1">
</ul>
<ul id="ul2">
</ul>
<ul id="ul3">
</ul>
</body>
i think you want is one of these:
Give the scope of counter to be global (yuk)
create a closure around everything and declare counter there
you could pass counter into loop() when you call it.
define loop() in changeDiv().
I think you want #2 though so I fiddled it with several corrections in your code:
fiddle
The reason that I went with #2 is:
that a closure allows your logic to gain application to the resources it needs
but protect the scope at which other applications might be running (now or in the future) from being affected by any changes your application might attempt to that scope. For example, if you declared the counter as a global then all other javascript would potentially have read/write access to it which could negatively affect your demonstrated code, the other code, or both
keeps your current beginner code as unchanged as possible
gets you programming with an extremely important aspect of javascript that will help you today and in future as you learn
Answer #4 is similar in that it would create a closure for both changeDiv and loop whereby they both have access to what they need. However, I didn't want to change your existing logical blocks too much to stall incremental learning. But one could definitely make an argument for the loop() (which isn't really a loop but rather a setter) being enclosed in changeDiv() -- albeit you would likely remove the separate function call at that point and integrate the code more.
Essentially, you need to:
declare counter in a global scope (loop() cannot access it otherwise)
in loop(), the return statement must be the LAST thing. Anything after it won't get executed.
I altered the logic a bit and the final code is this:
window.onload = init;
var counter=1;
function init(){
var button = document.getElementById("submit");
button.onclick = changeDiv;
}
function changeDiv(){
var name = "ul";
var textInput = document.getElementById("textInput");
var userInput = textInput.value;
var id = "ul" + loop();
alert("adding " + userInput + " to " + id);
var li = document.createElement("li");
li.innerHTML = userInput;
var ul = document.getElementById(id);
ul.appendChild(li);
}
function loop(){
var tmp = counter++;
if (counter==4){
counter=1;
}
return tmp;
}
Note the changes in the loop() function.
I also altered the changeDiv() function to display the list ID in the alert.

Change the onClick function to target the edit buttons

I have the following script
var counter = 0;
function appendText(){
var text = document.getElementById('usertext').value;
if ( document.getElementById('usertext').value ){
var div = document.createElement('div');
div.className = 'divex';
var li = document.createElement('li');
li.setAttribute('id', 'list');
div.appendChild(li);
var texty = document.createTextNode(text);
var bigdiv = document.getElementById('addedText');
var editbutton = document.createElement('BUTTON');
editbutton.setAttribute('id', 'button_click');
var buttontext = document.createTextNode('Edit');
editbutton.appendChild(buttontext);
bigdiv.appendChild(li).appendChild(texty);
bigdiv.appendChild(li).appendChild(editbutton);
document.getElementById('button_click').setAttribute('onClick', makeAreaEditable());
document.getElementById('usertext').value = "";
counter++;
}
};
var makeAreaEditable = function(){
alert('Hello world!');
};
I want the makeAreaeditable function to work when the Edit button is pressed(for each of the edit buttons that are appended under the textarea).. In this state, the script, alerts me when i hit the Addtext button.
the following is the html. P.S. i need this in pure javascript, if you can help. thanks
<textarea id="usertext"></textarea>
<button onClick="appendText()">Add text </button>
<div id="addedText" style="float:left">
</div>
instead of:
document.getElementById('button_click').setAttribute('onClick', makeAreaEditable());
you need to do this:
editbutton.onclick = makeAreaEditable;
the function's name goes without brackets unless you want to execute it
instead of obtaining the element from the DOM using document.getElementById('button_click')
you can use the editbutton variable already created. this object is the DOM element you are looking for
SIDE NOTE:
the standard way to do it is to add the onclick property before appending the element

Categories