I am trying to make a Library project using vanilla JS and I can't understand the behaviour of removeChild() and addEventListener() in the code.
var myLibrary = [];
var content = document.querySelector(".content");
var nameField = document.createElement("input");
var authorField = document.createElement("input");
var pagesField = document.createElement("input");
var readingStatusField = document.createElement("input");
var submitButton = document.createElement("button");
var form = document.createElement("form");
function Book(name, author, pages, status){
this.name = name;
this.author = author;
this.pages = pages;
this.status = status
}
Book.prototype.info = function(){
if(this.status === false){
return console.log(this.name + " " + "by " + this.author + "," + this.pages + " pages, " + "not read yet" )
}
else{
return console.log(this.name + " " + "by " + this.author + "," + this.pages + " pages, "+ "read" )
}
}
function addBookToLibrary(Book) {
myLibrary.push(Book);
}
function displayBooks(){
for(let x = 0; x < myLibrary.length; x++){
myLibrary[x].info();
}
}
function createBookForm() {
var form = document.createElement("form");
form.classList.add("book-form")
nameField.classList.add("formfield")
nameField.setAttribute("type", "text");
nameField.setAttribute("placeholder", "Name");
authorField.classList.add("formfield")
authorField.setAttribute("type", "text");
authorField.setAttribute("placeholder", "Author");
pagesField.classList.add("formfield")
pagesField.setAttribute("type", "text");
pagesField.setAttribute("placeholder", "Pages");
readingStatusField.classList.add("formfield")
readingStatusField.setAttribute("type", "text");
readingStatusField.setAttribute("placeholder", "Reading Status");
submitButton.innerHTML = "Add"
submitButton.classList.add("submitButton")
submitButton.setAttribute("type", "submit");
submitButton.setAttribute("value", "Submit");
// submitButton.onclick("")
form.appendChild(submitButton);
form.appendChild(readingStatusField);
form.appendChild(pagesField);
form.appendChild(authorField);
form.appendChild(nameField);
content.appendChild(form);
}
function getInfoFromForm() {
submitButton.addEventListener('click', (e) => {
let bookName = nameField.value;
let authorName = authorField.value;
let noOfPages = pagesField.value;
let readingStatus = readingStatusField.value;
let newBook = new Book(bookName, authorName, noOfPages, readingStatus);
addBookToLibrary(newBook);
displayBooks();
nameField.value = "";
authorField.value = "";
pagesField.value = "";
readingStatusField.value = "";
content.innerHTML = ""
content.removeChild(form);
})
}
let addBookButton = document.querySelector(".addBook");
addBookButton.addEventListener("click", (e) => {
let content = document.querySelector(".content")
createBookForm();
getInfoFromForm();
deleteForm();
})
In createBookForm() function, I create a form and append it to the content div. It worked fine.
In getInfoFromForm() function, I try to get info from the form, and when submit button is clicked I want to create an Book object and store it in the myLibrary[] array.
Here things get out of hand for me.
First of all, the removeChild method doesnt work and doesn't remove the form element from the content.
Second when I try to console.log the books from myLibrary[], at first submit it shows correctly. When I try this second time, it shows the first book, second book THREE TIMES and an empty book.
WHY ISN'T removeChild removing the form element and why is cicking the submit button behaves the way it is behaving.
Related
I like to add an input field to my list element for the timer im working on.
The problem is that it can read the function but doesnt display the object.
//Input Element Object
function inputElement() {
this.input = document.createElement("input");
this.input.id = "Timer " + count
this.input.type = "number";
this.input.max = 10;
this.input.min = 01;
}
function LI(id) {
this.li = document.createElement("li");
this.li.id = id;
this.li.id += count;
this.input = new inputElement();
this.li.innerHTML += this.input + ` set Timer`;
this.setting = document.getElementById("Version3");
this.setting.append(this.li);
}
I already have this JavaScript code inside a function called add().
var newinput = document.createElement('div');
newinput.innerHTML = "<br><input type='file' id='" + counter +
"'name='filename[" + counter +
"]' accept='image/jpeg' onchange='add()'>";
document.getElementById('asd').appendChild(newinput);
But instead of this innerHTML I want to do this new function:
var newinput = document.createElement('input');
newinput.id=x;
newinput.type="file";
newinput.name="filename";
newinput.accept="image/jpeg";
newinput.onchange=add();
Thus far, the new function creates an input like the innerHTML one of the first function, but doesn't add the onchange property (and the full created input even disapears, so I have to comment the .onchange();
Is there a way I can add the ".onchange" to the createElement var or create a JavaScript listener for a couple inputs like input.onchange() = function (){}? Thanks.
As it currently is, you are expecting add() to return a function. Do not invoke the function and just do:
newinput.onchange = add;
(function() {
function add() {
console.log("Added.");
}
function createFileInput(x) {
var newinput = document.createElement('input');
newinput.id = x;
newinput.type = "file";
newinput.name = "filename";
newinput.accept = "image/jpeg";
newinput.onchange = add;
return newinput;
}
document.body.appendChild(createFileInput('my-input'));
})();
Here's an example of what you were doing, and how it would work:
(function() {
function add() {
return function() {
console.log("Added.");
}
}
function createFileInput(x) {
var newinput = document.createElement('input');
newinput.id = x;
newinput.type = "file";
newinput.name = "filename";
newinput.accept = "image/jpeg";
newinput.onchange = add();
return newinput;
}
document.body.appendChild(createFileInput('my-input'));
})();
trying to do javascript app that should have 4 inputs - user, mail, phone address
add new user / delete user details to/from the list buttons (popup should appear to confirm). Get stuck adding multiple users.
here is the code in a jsfiddle
The var seem to be objects HTMLElements
<div class="container">
<p>
<label for="new-task">Add Item</label><input id="new" type="text"><input id="new" type="text"><input id="new" type="text"> <input id="new" type="text"><button>Add</button>
</p>
<h3>Todo</h3>
<ul id="current-tasks">
<li><label> Learn </label><button class="delete">Delete</button></li>
<li><label>Read</label><button class="delete">Delete</button></li>
</ul>
<script>
var nameInput = document.getElementById("new-name");
var emailInput = document.getElementById("new-email");
var noInput = document.getElementById("new-phone");
var zipInput = document.getElementById("new-zip");
// var = nameInput + " " + emailInput + " " + noInput + " " + zipInput;
// console.log(nameInput);
// console.log(taskInput.innerText);
// var taskInput = nameInput.concat(emailInput);
// document.querySelectorAll("new-name, new-email, new-number, new-zip");
// var taskInput = nameInput + " " + emailInput + " " + noInput + " " + zipInput;
// var taskInput = nameInput.concat(emailInput);
// document.querySelectorAll("new-name, new-email, new-number, new-zip");
var addButton = document.getElementsByTagName("button")[0]; //first button
var cTasksHolder = document.getElementById("current-tasks"); //current-tasks
var delButton= document.getElementsByClassName("delete");
//New Task List Item
var createNewTaskElement = function(taskString) {
//Create List Item
var listItem = document.createElement("li");
var label = document.createElement("label");
var deleteButton = document.createElement("button");
deleteButton.innerText = "Delete";
deleteButton.className = "delete";
label.innerText = taskString;
//each element need appending
listItem.appendChild(label);
listItem.appendChild(deleteButton);
return listItem;
alert(listItem);
}
// adauga task
var addTask = function() {
console.log("Add task...");
var nnameInput = nameInput.value;
var nemailInput = emailInput.value);
var nnoInput = noInput.value;
var nzipInput = zipInput.value);
var tInput = [nnameInput, nemailInput , nnoInput, nzipInput];
var taskInput = tInput.join(", ");
alert(taskInput.value);
alert(taskInput);
var listItem = createNewTaskElement(taskInput.value);
console.log(taskInput.value);
//apend listItems to imcomplete taskHolder (only if task is not null)
if(taskInput.value) {
cTasksHolder.appendChild(listItem);
bindTaskEvents(listItem);
} else {
alert("You must enter the name , the email , the phone and the zip code.");
}
}
var deleteTask = function() {
console.log("Delete task...");
var listItem = this.parentNode;
var ul = listItem.parentNode;
ul.removeChild(listItem);
}
var bindTaskEvents = function(taskListItem){
console.log("Bind list item events");
var deleteButton = taskListItem.querySelector("button.delete");
deleteButton.onclick = deleteTask;
} addButton.onclick = addTask;
for (var i = 0; i < cTasksHolder.children.length; i++) {
console.log(cTasksHolder.children[i]);
bindTaskEvents(cTasksHolder.children[i]);
}
</script>
You are missing the call for the values of the inputs. When you call at the beginning the document.getElementById(), you use this var to create stuff, when what you need is it's value, like so:
var nameInput = document.getElementById("new-name")
var nnameInput = nameInput.value;
EDIT - There was multiple wrong things, I'll list them here along with an updated jsfiddle.
In addTask, you had the line "console.log(string);;", it was crashing because of double ";" and because you were trying to print a 'string' var, that didn't exist.
You didn't add ".value" when you call "nameInput" so the code was working with elements rather than strings.
There was no need to write "var nnameInput = nameInput;" in function addTask
You wrote "var listItem = createNewTaskElement(taskInput.value);" but there was no need for the value, as the taskInput is already a string that was joined by ',' previously.
And you do the same as the above in the "if (taskInput.value) {", where it should be "if (taskInput) {"
http://jsfiddle.net/filipetedim/u27Lytqt/4/
So I was in the presumption that this function
button.onclick = exampleFunk;
would give me a handler on each button when I click them, but it doesn't. When replacing it with:
button.onclick = alert("bananas");
I'm getting alerts at page onload. The problem is already solved with this:
button.setAttribute("onclick", "removeIssue(this)");
Out of curiousity... What's going on?
edited layout of post
EDIT
var issues = [];
window.onload = function () {
//alert("venster geladen");
issuesToList()
}
function issuesToList(data) {
/*alert(
"array length is " + data.issues.length + "\n" +
"total_count is " + data.total_count + "\n" +
"limit is " + data.limit + "\n" +
"offset is " + data.offset + "\n" + ""
);*/
for (i = 0; i < data.issues.length; i++) {
issue = data.issues[i];
createIssue(issue);
}
}
function createIssue(issue){
var id = issue.id;
var tracker = issue.tracker;
var status = issue.status;
var priority = issue.priority;
var subject = issue.subject;
var description = issue.description;
var assignee = issue.assignee;
var watchers = issue.watchers;
var ticket = new Issue(id, tracker, status, priority, subject, description, assignee, watchers);
issues.push(ticket);
var button = document.createElement("button");
button.innerHTML = "-";
button.onclick = function (){ alert("bananas")};
//button.setAttribute("onclick", "removeIssue(this)");
var item = document.createElement("div");
item.setAttribute("id", id);
item.appendChild(button);
item.innerHTML += " " + subject;
var container = document.getElementById("container");
container.appendChild(item);
}
function removeIssue(e){
var key = e.parentNode.getAttribute("id");
var count = issues.length;
if(confirm("Confirm to delete")){
for(i=0; i<count; i++){
if (issues[i].id == key ){
issues.splice(i,1);
var element = document.getElementById(key);
element.parentNode.removeChild(element);
}
}
}
}
function Issue(id, tracker, status, priority, subject, description, assignee, watchers){
this.id = id;
this.tracker = tracker;
this.status = status;
this.priority = priority;
this.subject = subject;
this.description = description;
this.assignee = assignee;
this.watchers = watchers;
}
EDIT
<body>
<h1>List of Issues</h1>
<div id="container"></div>
<script src="http://www.redmine.org/issues.json?limit=10&callback=issuesToList"></script>
</body>
You need to mask the alert in a function:
button.onclick = function (){ alert("bananas")};
As such:
var btn = document.createElement("BUTTON");
var t = document.createTextNode("CLICK ME");
btn.appendChild(t);
btn.onclick = function() {alert("bananas")};
document.body.appendChild(btn);
Whats going on?
You alert() is executed on page load because its a function call. When the execution of your script reaches that line your assignment
button.onclick = alert("bananas");
is actually executing the alert statement and not assigning it to button.onclick
You can bind arguments to the function so that it returns with the function you want it to call using your arguments (with additional arguments passed later added on to the end). This way doesn't require writing extraneous code (when all you want to do is call a single function) and looks a lot sleeker. See the following example:
button.onclick = alert.bind(window, "bananas");
An unrelated example of how it works in your own code is like this:
var alert2 = alert.bind(window, 'Predefined arg');
alert2(); // 'Predefined arg'
alert2('Unused'); // 'Predefined arg'
For IE, this requires IE9 as a minimum. See MDN for more information.
EDIT: I've looked closer at your code and there was one significant change that was needed for it to work... You cannot add onto the innerHTML when you've added JavaScript properties to a child element. Changing the innerHTML of the parent element will convert your element into HTML, which won't have the onclick property you made before. Use element.appendChild(document.createTextNode('My text')) to add text dynamically.
See a functioning example here: http://jsfiddle.net/2ftmh0gh/2/
Ok, here is the thing.
I have posted 2 days in a row and you guys have helped me a lot! And know I am almost done with the project, only a few things left, and a will ask another question later here.
But to the point!
I am trying to use the .style.display = ... in my javascript and it doesnt work.
I dont know if the function isnt calling or if I have done it all wrong?
What I am trying to accomplish is that when I press the button "newButton" I got a form field, and after I am finished with the form I press the button "addContact" that is created with the form all dynamically with javascript I want the form to hide. How can I do that?
The form is not gonna submit to a php and that is why a have button and not submit, because the form is gonna display at the HTML (DOM) and show like a contactlist.
Hope you could help me out!
Here is the code.
//Contactlist funktion
function Contact(fname, lname, address, email, phone) {
this.fname = fname;
this.lname = lname;
this.address = address;
this.email = email;
this.phone = phone;
}
//The contacts
var contacts = [];
var ul1 = document.createElement('ul');
ul1.id = ('nav');
// Appending the objects
function theContacts() {
var body = document.getElementsByTagName('body')[0],
length = contacts.length;
for (var i = 0; i < length; i++) {
var cont = contacts[i],
li = document.createElement('li'),
ul = document.createElement('ul');
li.innerHTML = cont.fname + ' ' + cont.lname;
for (var key in cont) {
var info = document.createElement('li');
info.className = key;
info.innerHTML = cont[key];
ul.appendChild(info);
}
li.appendChild(ul); ul1.appendChild(li);
}
body.appendChild(ul1);
}
// Calling the object
function addForms(){
var body = document.getElementsByTagName('body')[0]
var form = document.createElement("form");
form.id = 'formList';
var myArray = ['fnameValue', 'lnameValue', 'addressValue', 'emailValue', 'phoneValue'];
var texts = ['First Name: ', 'Last Name: ', 'Address: ', 'Email: ', 'Phone: '];
// Create a loop of 5
for(var i = 0; i < 5; i++){
var input = document.createElement('input');
var newlabel = document.createElement('label');
newlabel.innerHTML = texts[i];
form.appendChild(newlabel);
input.setAttribute('type','text');
input.setAttribute('id', myArray[i]);
// adds the input's to the form.
form.appendChild(input);
}
// adds the forms to the body
body.appendChild(form);
// Add Contact Button
var addContact = document.createElement('input')
addContact.setAttribute('type', 'button')
addContact.setAttribute('id', 'addContact')
addContact.addEventListener('click', onClick);
addContact.setAttribute('value', 'Add Contact')
form.appendChild(addContact);
/* var knapp = document.getElementById('addContact');
knapp.addEventListener('click', addNewContact) */
}
function addNewContact() {
var input1 = document.getElementById('fnameValue').value;
var input2 = document.getElementById('lnameValue').value;
var input3 = document.getElementById('addressValue').value;
var input4 = document.getElementById('emailValue').value;
var input5 = document.getElementById('phoneValue').value;
contacts.length = 0;
contacts.push(new Contact(input1, input2, input3, input4, input5));
}
// Knappning för ny kontakt
var button = document.getElementById("newButton");
button.addEventListener("click", addForms);
Here is the last part of the code that I am trying to apply but doesnt work for me...
function onClick() {
var div = document.getElementById('formlist');
if (addForms.style.display !== 'none') {
addForms.style.display = 'none';
}
else {
addForms.style.display = 'block';
}
};
Here you have an JS FIDDLE for example: http://jsfiddle.net/192ds38a/
That one shows how it works now withuot the "onClick" function.
But what I want is to hide the form when the AddContact button is pressed. That button is now made to add the information to the objects, but I also want that to hide the form.
Simply add a document.getElementById("formList").remove()to the addNewContact function as you can see in http://jsfiddle.net/192ds38a/1/ . Or does this not meet your needs?