I have this program that can make closables dynamically. When the user clicks on a created closable an input box and a button are displayed in the content of the closable. The user can then input text into the textbox and then press the button. Then the users text will be displayed in the selected closable content.
Everything works, fine except for when I try to append the users input to the selected closable. I'm trying to append the users input with this function, but it doesn't work:
var taskCounter = 0;
function addTask() {
var text = document.getElementById("taskInput").value;
console.log(text);
var newTask = $("<input type='checkbox'><label>"+ text + "</label><br>");
newTask.id = 'temp' + taskCounter;
console.log(newTask.id);
taskCounter++
var newContent = document.createTextNode(text);
$(currentContent).append(newTask); //where is it being append to??
console.log("added") //it say it added but where?
}
Why isn't the users input being displayed in the selected closable? And if I'm not doing this correctly already, how do you append a dynamically created element to an elements nextElementSibling?
Here is my full code:
var currentClosable;
var currentContent;
function selectedColl(){
document.getElementById("inputTaskDiv").style.display = "block";
currentClosable = event.target;
currentContent = currentClosable.nextElementSibling;
console.log(currentContent);
var inputTaskDiv = document.getElementById("inputTaskDiv");
currentContent.append(inputTaskDiv);
}
var taskCounter = 0;
function addTask() {
var text = document.getElementById("taskInput").value;
// create a new div element and give it a unique id
var newTask = $("<input type='checkbox'><label>"+ text + "</label><br>");
newTask.id = 'temp' + taskCounter;
taskCounter++
// and give it some content
var newContent = document.createTextNode(text);
$(currentContent).append(newTask); //where is it being append to????
}
var elementCounter = 0;
var elementCounterContent = 0;
var text;
function addElement() {
text = document.getElementById("input").value;
// create a new div element and give it a unique id
var newDiv = $("<button class='collapsible' onclick='selectedColl()'></button>").text(text);
var newContentOfDiv = $("<div class='content'></div>");
newDiv.id = 'temp' + elementCounter;
newContentOfDiv.id = 'content' + elementCounterContent;
newDiv.classList = "div";
elementCounter++
elementCounterContent++
// and give it some content
var newContent = document.createTextNode(text);
// add the newly created element and its content into the DOM
document.getElementById("input").value = " ";
$("body").append(newDiv, newContentOfDiv);
newDiv.click(function() {
this.classList.toggle("active");
content = this.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
.collapsible {
background-color: #777;
color: white;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
}
.active, .collapsible:hover {
background-color: #555;
}
.collapsible:after {
content: '\002B';
color: white;
font-weight: bold;
float: right;
margin-left: 5px;
}
.active:after {
content: "\2212";
}
.content {
padding: 0 18px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<input id="input" type="text"><button onclick="addElement()">Add</button>
<div id="inputTaskDiv" style="display:none">
<input id="taskInput" type="text"><button onclick="addTask()">Add Task</button>
</div>
Related
In this test case, I am using append.child with plain JavaScript to add 3 kinds of divs (blue, red, green) to a parent multiple times according to their corresponding button onclicks, then I am adding another child inside the added div with another button (innerButton).
My issue is that, the onclick function which is assigned to the innerbutton and is nested within the initial function, listens only to the very first appended div, and it adds the input (which is supposed to be added to the div I'm clicking on) to the last append element of its 'kind'.
I am doing something wrong with my scoping but I can't see it.
I just started studying JavaScript, so I am not familiar yet with libraries, jQuery etc.
var countBlue = 0;
var countRed = 0;
var countGreen = 0;
function addBlue() {
var addTo = document.getElementById('div1')
var blue = document.createElement("div");
blue.id = "blueDiv";
blue.innerHTML = "<input id=blueInput><button id=innerButtonBlue onclick=addInputs()>ADD INPUTS</button>";
addTo.appendChild(blue);
document.getElementById("innerButtonBlue").onclick = function() {
var newInput = document.createElement("div");
newInput.innerHTML = '<input id="newInput" placeholder="NEW">';
blue.appendChild(newInput);
}
countBlue++;
}
function addRed() {
var addTo = document.getElementById('div1')
var red = document.createElement("div");
red.id = "redDiv";
red.innerHTML = "<input id=redInput><button id=innerButtonRed>ADD INPUTS</button>";
addTo.appendChild(red);
document.getElementById("innerButtonRed").onclick = function() {
var newInput = document.createElement("div");
newInput.innerHTML = '<input id="newInput" placeholder="NEW">';
red.appendChild(newInput);
}
countRed++;
}
function addGreen() {
var addTo = document.getElementById('div1')
var green = document.createElement("div");
green.id = "greenDiv";
green.innerHTML = "<input id=greenInput><button id=innerButtonGreen>ADD INPUTS</button>";
addTo.appendChild(green)
document.getElementById("innerButtonGreen").onclick = function() {
var newInput = document.createElement("div");
newInput.innerHTML = '<input id="newInput" placeholder="NEW">';
green.appendChild(newInput);
}
countGreen++;
}
function displayCounters() {
alert("Blue divs amount : " + parseInt(countBlue) + "\n" + " Red divs amount : " + parseInt(countRed) + "\n" + " Green divs amount : " + parseInt(countGreen) + "\n" + "\n" + " All together is : " + (parseInt(countBlue) + parseInt(countRed) + parseInt(countGreen)))
}
button {
margin-bottom: 10px;
}
#blueDiv {
margin-top: 10px;
margin-bottom: 10px;
width: 300px;
}
#redDiv {
margin-top: 10px;
margin-bottom: 10px;
width: 300px;
}
#greenDiv {
margin-top: 10px;
margin-bottom: 10px;
width: 300px;
}
input {
text-align: center;
}
#innerButtonRed {
position: relative;
float: right;
}
#innerButtonBlue {
position: relative;
float: right;
}
#innerButtonGreen {
position: relative;
float: right;
}
#newInput {
margin-top: 2px;
width: 162px;
height: 23px;
}
#redInput {
background: red;
}
#blueInput {
background: blue;
}
#greenInput {
background: green;
}
<html>
<body>
<script src="test.js"></script>
<link rel="stylesheet" type="text/css" href="test.css">
<button onclick="addBlue()">BLUE</button>
<button onclick="addRed()">RED</button>
<button onclick="addGreen()">GREEN</button>
<button onclick="displayCounters()">COUNTERS</button>
<div id="div1"></div>
</body>
</html>
The first thing you need to know is that, although you can technically add the same id to multiple elements, it is bad practice to do so. The id of an element should be unique. If you need to apply the same style or target multiple elements with your code you should use class instead of id.
I think that's what is causing issues in your code.
Second, since you say you are learning, i think it would be good if you tried to make a single function to add the elements since the code is repeated in all of the three functions, except for the color.
Try making the function accept the color as a variable so you can reuse it for the three colors. Imagine if it was a hundred colors.
var countBlue = 0;
var countRed = 0;
var countGreen = 0;
function addBlue() {
var addTo = document.getElementById('div1')
var div = document.createElement("div");
countBlue++; //set the counter to one so ids don't start at zero
div.id = `blueDiv-${countBlue}`; //creates a unique id depending on the counter
div.classList = "blueDiv";
div.innerHTML = `<input id="blueInput-${countBlue}" class="blueInput"><button id="innerButtonBlue-${countBlue}" onclick="addInputs">ADD INPUTS</button>`;
addTo.appendChild(div);
document.getElementById(`innerButtonBlue-${countBlue}`).onclick = function() {
var newInput = document.createElement("div");
newInput.innerHTML = `<input id="newInput-blue-${countBlue}" class="newInput" placeholder="NEW">`;
div.appendChild(newInput);
}
}
function addRed() {
var addTo = document.getElementById('div1')
var div = document.createElement("div");
countRed++
div.id = `redDiv-${countRed}`;
div.classList = "redDiv";
div.innerHTML = `<input id="redInput-${countRed}" class="redInput"><button id="innerButtonRed-${countRed}" onclick="addInputs">ADD INPUTS</button>`;
addTo.appendChild(div);
document.getElementById(`innerButtonRed-${countRed}`).onclick = function() {
var newInput = document.createElement("div");
newInput.innerHTML = `<input id="newInput-red-${countRed}" class="newInput" placeholder="NEW">`;
div.appendChild(newInput);
}
}
function addGreen() {
var addTo = document.getElementById('div1')
var div = document.createElement("div");
countGreen++
div.id = `greenDiv-${countGreen}`;
div.classList = "greenDiv";
div.innerHTML = `<input id="greenInput-${countGreen}" class="greenInput"><button id="innerButtonGreen-${countGreen}" onclick="addInputs">ADD INPUTS</button>`;
addTo.appendChild(div);
document.getElementById(`innerButtonGreen-${countGreen}`).onclick = function() {
var newInput = document.createElement("div");
newInput.innerHTML = `<input id="newInput-green-${countGreen}" class="newInput" placeholder="NEW">`;
div.appendChild(newInput);
}
}
function displayCounters() {
alert("Blue divs amount : " + parseInt(countBlue) + "\n" + " Red divs amount : " + parseInt(countRed) + "\n" + " Green divs amount : " + parseInt(countGreen) + "\n" + "\n" + " All together is : " + (parseInt(countBlue) + parseInt(countRed) + parseInt(countGreen)))
}
button {
margin-bottom: 10px;
}
.blueDiv {
margin-top: 10px;
margin-bottom: 10px;
width: 300px;
}
.redDiv {
margin-top: 10px;
margin-bottom: 10px;
width: 300px;
}
.greenDiv {
margin-top: 10px;
margin-bottom: 10px;
width: 300px;
}
input {
text-align: center;
}
.innerButtonRed {
position: relative;
float: right;
}
.innerButtonBlue {
position: relative;
float: right;
}
.innerButtonGreen {
position: relative;
float: right;
}
.newInput {
margin-top: 2px;
width: 162px;
height: 23px;
}
.redInput {
background: red;
}
.blueInput {
background: blue;
}
.greenInput {
background: green;
}
<button onclick="addBlue()">BLUE</button>
<button onclick="addRed()">RED</button>
<button onclick="addGreen()">GREEN</button>
<button onclick="displayCounters()">COUNTERS</button>
<div id="div1"></div>
IDs need to be unique in the whole document. Don't use IDs for this, you can just use a class. But even with a class how is the code supposed to know which element it should look for since there will be more than one existing with the class? The solution is to search only inside the element that you just created (e.g. blue.querySelector('.someClass') to search for the first element with class someClass inside the blue element).
I changed your code to use classes everywhere:
var countBlue = 0;
var countRed = 0;
var countGreen = 0;
function addBlue() {
var addTo = document.getElementById('div1')
var blue = document.createElement("div");
blue.className = "blueDiv";
blue.innerHTML = "<input class='firstInput'><button class='innerButton'>ADD INPUTS</button>";
addTo.appendChild(blue);
blue.querySelector(".innerButton").onclick = function() {
var newInput = document.createElement("div");
newInput.innerHTML = '<input class="newInput" placeholder="NEW">';
blue.appendChild(newInput);
}
countBlue++;
}
function addRed() {
var addTo = document.getElementById('div1')
var red = document.createElement("div");
red.className = "redDiv";
red.innerHTML = "<input class='firstInput'><button class='innerButton'>ADD INPUTS</button>";
addTo.appendChild(red);
red.querySelector(".innerButton").onclick = function() {
var newInput = document.createElement("div");
newInput.innerHTML = '<input class="newInput" placeholder="NEW">';
red.appendChild(newInput);
}
countRed++;
}
function addGreen() {
var addTo = document.getElementById('div1')
var green = document.createElement("div");
green.className = "greenDiv";
green.innerHTML = "<input class='firstInput'><button class='innerButton'>ADD INPUTS</button>";
addTo.appendChild(green)
green.querySelector(".innerButton").onclick = function() {
var newInput = document.createElement("div");
newInput.innerHTML = '<input class="newInput" placeholder="NEW">';
green.appendChild(newInput);
}
countGreen++;
}
function displayCounters() {
alert("Blue divs amount : " + parseInt(countBlue) + "\n" + " Red divs amount : " + parseInt(countRed) + "\n" + " Green divs amount : " + parseInt(countGreen) + "\n" + "\n" + " All together is : " + (parseInt(countBlue) + parseInt(countRed) + parseInt(countGreen)))
}
button {
margin-bottom: 10px;
}
.blueDiv {
margin-top: 10px;
margin-bottom: 10px;
width: 300px;
}
.redDiv {
margin-top: 10px;
margin-bottom: 10px;
width: 300px;
}
.greenDiv {
margin-top: 10px;
margin-bottom: 10px;
width: 300px;
}
input {
text-align: center;
}
.redDiv .innerButton {
position: relative;
float: right;
}
.blueDiv .innerButton {
position: relative;
float: right;
}
.greenDiv .innerButton {
position: relative;
float: right;
}
.newInput {
margin-top: 2px;
width: 162px;
height: 23px;
}
.redDiv .firstInput {
background: red;
}
.blueDiv .firstInput {
background: blue;
}
.greenDiv .firstInput {
background: green;
}
body {
height: 800px; /* Just for visibility here in Stack Overflow */
}
<html>
<body>
<script src="test.js"></script>
<link rel="stylesheet" type="text/css" href="test.css">
<button onclick="addBlue()">BLUE</button>
<button onclick="addRed()">RED</button>
<button onclick="addGreen()">GREEN</button>
<button onclick="displayCounters()">COUNTERS</button>
<div id="div1"></div>
</body>
</html>
There is a lot more that could be improved of course - the code duplication could be removed, a generalized function for all three types (red/green/blue) can be created that is differentiated just by an attribute on the button for example - but that's beyond the scope of this answer.
I am pretty new to js. I am trying to complete a todo sort of app. I have been able to create, render and delete an array item, but I am having trouble editing.
All these operations are done with the uuidv4 library to generate an id for each array item created.
With an individual id selected for an array item, I am generating dynamic buttons, one for deleting the array item, the other one for editing.
Upon clicking edit, I want to open up a modal that contains the content of the selected array item. After making the changes, the edit button inside the modal should call upon an edit function to update the changes and then rerender the array.
My issue is that I can't open up the modal dialog box when clicking the edit button.
This is the code to create the necessary structure, the code for creating, rendering and deleting is not included as they are working properly.
// Generate the DOM structure for a todo
const generateTodoDOM = function(todo) {
const todoEl = document.createElement("div");
const checkbox = document.createElement("input");
const label = document.createElement("label");
checkbox.appendChild(label);
todoEl.setAttribute("id", "myTodos");
const textEl = document.createElement("p");
const editButton = document.createElement("button");
editButton.setAttribute("id", "modal-btn");
const removeButton = document.createElement("button");
const createDate = document.createElement("p");
createDate.textContent = `Created: ${dateCreated}`;
createDate.style.color = "#956E93";
// Setup the todo text
textEl.textContent = todo.text;
todoEl.appendChild(textEl);
// Setup the remove button
removeButton.textContent = "x";
todoEl.appendChild(removeButton);
removeButton.addEventListener("click", function() {
removeTodo(todo.id);
saveTodos(todos);
renderTodos(todos, filters);
});
// TODO: Setup the edit note button
editButton.textContent = "Edit Todo";
todoEl.appendChild(editButton);
editButton.addEventListener("click", function() {
//Launch the modal
editModal(todo.id);
});
// Setup todo checkbox
checkbox.setAttribute("type", "checkbox");
checkbox.checked = todo.completed;
todoEl.appendChild(checkbox);
checkbox.addEventListener("change", function() {
toggleTodo(todo.id);
saveTodos(todos);
renderTodos(todos, filters);
});
todoEl.appendChild(createDate);
return todoEl;
};
The code for the modal is the following:
//Edit modal todo by id
const editModal = function(id) {
const todoIndex = todos.findIndex(function(todo) {
return todo.id === id;
});
if (todoIndex > -1) {
const modal = document.querySelector("#my-modal");
const modalBtn = document.querySelector("#modal-btn");
const editTodoContentBtn = document.querySelector("#submitEditTodo")
const closeBtn = document.querySelector(".close");
// Events
modalBtn.addEventListener("click", openModal);
closeBtn.addEventListener("click", closeModal);
editTodoContentBtn.addEventListener("click", editTodo)
window.addEventListener("click", outsideClick);
// Open
function openModal() {
modal.style.display = "block";
}
// Close
function closeModal() {
modal.style.display = "none";
}
// Close If Outside Click
function outsideClick(e) {
if (e.target == modal) {
modal.style.display = "none";
}
}
//Edit the content of the textarea
function editTodo(e) {
editTodo(id)
}
}
};
When clicking the submitEditTodo button the following edit function should be fired:
//Edit todo by id
const editTodo = function(id) {
const editTodoContent = document.querySelector('#editTodo')
const todoIndex = todos.findIndex(function(todo) {
return todo.id === id;
});
if (todoIndex > -1) {
editTodoContent.value = todos.text
saveTodos(todos)
renderTodos(todos, filters);
}
};
The saveTodos and renderTodos are functioning properly with other functions for creating, rendering and deleting.
This is the HTML code:
<!-- Edit modal -->
<div id="my-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close">×</span>
<h2>Edit Todo</h2>
</div>
<div class="modal-body">
<textarea name="" class="editTextArea" id="editTodo" rows="10"></textarea>
<button class="button" id="submitEditTodo">Edit Todo</button>
</div>
<div class="modal-footer">
<!-- <h3>Modal Footer</h3> -->
</div>
</div>
<!-- End modal -->
and this is the CSS for the modal:
/*
Edit todo modal start
*/
:root {
--modal-duration: 1s;
--modal-color: #BB8AB8;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
height: 100%;
width: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
margin: 10% auto;
width: 35%;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.17);
animation-name: modalopen;
animation-duration: var(--modal-duration);
}
.editTextArea{
width:100%
}
.modal-header h2,
.modal-footer h3 {
margin: 0;
}
.modal-header {
background: var(--modal-color);
padding: 15px;
color: #fff;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.modal-body {
padding: 10px 20px;
background: #fff;
}
.modal-footer {
background: var(--modal-color);
padding: 10px;
color: #fff;
text-align: center;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.close {
color: #ccc;
float: right;
font-size: 30px;
color: #fff;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
#keyframes modalopen {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/*
Edit todo modal end
*/
Thanks
Below are a few pointers to where you might need adjustments to achieve what you want.
Currently you are adding new listeners to the modal every time you click an edit button for a todo. This should probably only be set once. Alternatively you should remove the listeners when the modal is closed.
Your function editModal does not actually open the modal. What it does is add a listener to the #modal-btn button which will then open the modal the next time you click the button.
You are setting id's for both the outer div and the edit button, but the id's are not based on anything related to the todo element you are creating. So effectively all those elements end up with the same id. An id (short for identifier) is usually meant to be unique. For grouping of multiple elements you should instead use the class attribute.
Your function "editTodo" calls itself. Recursing indefinitely. Beware of reusing function names.
With that said the below code is a crude way to do what I think you want to do based on the snippets you provided:
// Open
const openModal = function() {
document.querySelector("#my-modal").style.display = "block";
}
// Close
const closeModal = function() {
document.querySelector("#my-modal").style.display = "none";
}
function initModal() {
const modal = document.querySelector("#my-modal");
const closeBtn = document.querySelector(".close");
// Events
closeBtn.addEventListener("click", closeModal);
window.addEventListener("click", outsideClick);
// Close If Outside Click
function outsideClick(e) {
if (e.target == modal) {
modal.style.display = "none";
}
}
}
const filters = []; // dummy variable
// Generate the DOM structure for a todo
var todos = []
function generateTodoDOM(todo) {
todos.push(todo);
const todoEl = document.createElement("div");
const checkbox = document.createElement("input");
const label = document.createElement("label");
checkbox.appendChild(label);
todoEl.setAttribute("id", "my-todos-" + todo.id);
const textEl = document.createElement("p");
const editButton = document.createElement("button");
editButton.setAttribute("id", "modal-btn-" + todo.id);
const removeButton = document.createElement("button");
const createDate = document.createElement("p");
createDate.textContent = 'Created: ' + new Date();
createDate.style.color = "#956E93";
// Setup the todo text
textEl.textContent = todo.text;
todoEl.appendChild(textEl);
// Setup the remove button
removeButton.textContent = "x";
todoEl.appendChild(removeButton);
removeButton.addEventListener("click", function() {
removeTodo(todo.id);
saveTodos(todos);
renderTodos(todos, filters);
});
// TODO: Setup the edit note button
editButton.textContent = "Edit Todo";
todoEl.appendChild(editButton);
editButton.addEventListener("click", function() {
//Launch the modal
editModal(todo.id);
openModal();
});
// Setup todo checkbox
checkbox.setAttribute("type", "checkbox");
checkbox.checked = todo.completed;
todoEl.appendChild(checkbox);
checkbox.addEventListener("change", function() {
toggleTodo(todo.id);
saveTodos(todos);
renderTodos(todos, filters);
});
todoEl.appendChild(createDate);
return todoEl;
};
var editFn
//Edit modal todo by id
const editModal = function(id) {
const todoIndex = todos.findIndex(function(todo) {
return todo.id === id;
});
if (todoIndex > -1) {
const modal = document.querySelector("#my-modal");
const editElm = document.querySelector("#editTodo");
const editTodoContentBtn = document.querySelector("#submitEditTodo")
editElm.value = todos[todoIndex].text;
// Events
editTodoContentBtn.removeEventListener("click", editFn)
//Edit the content of the textarea
editFn = function(e) {
editTodo(id)
closeModal()
}
editTodoContentBtn.addEventListener("click", editFn)
}
};
//Edit todo by id
const editTodo = function(id) {
const editTodoContent = document.querySelector('#editTodo')
const todoIndex = todos.findIndex(function(todo) {
return todo.id === id;
});
if (todoIndex > -1) {
todos[todoIndex].text = editTodoContent.value;
saveTodos(todos)
renderTodos(todos, filters);
}
};
const saveTodos = function(todos) {
// dummy method, we're keeping it in memory for this example
}
const renderTodos = function(todosToRender) {
todos = []; // clear current in-memory array
var todoList = document.getElementById("todo-container");
while (todoList.firstChild) {
todoList.removeChild(todoList.firstChild);
}
for(var i = 0; i < todosToRender.length; i++) {
todoList.appendChild(generateTodoDOM(todosToRender[i]));
}
};
initModal();
const container = document.getElementById("todo-container");
var generatedTodos = [];
for(var i = 0; i < 10; i++) {
var todo = { text: "Todo " + (i+1), id: "todo-" + i, completed: false};
generatedTodos.push(todo);
}
renderTodos(generatedTodos);
/*
Edit todo modal start
*/
:root {
--modal-duration: 1s;
--modal-color: #BB8AB8;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
height: 100%;
width: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
margin: 10% auto;
width: 35%;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.17);
animation-name: modalopen;
animation-duration: var(--modal-duration);
}
.editTextArea{
width:100%
}
.modal-header h2,
.modal-footer h3 {
margin: 0;
}
.modal-header {
background: var(--modal-color);
padding: 15px;
color: #fff;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.modal-body {
padding: 10px 20px;
background: #fff;
}
.modal-footer {
background: var(--modal-color);
padding: 10px;
color: #fff;
text-align: center;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.close {
color: #ccc;
float: right;
font-size: 30px;
color: #fff;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
#keyframes modalopen {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/*
Edit todo modal end
*/
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="todo-container">
</div>
<!-- Edit modal -->
<div id="my-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close">×</span>
<h2>Edit Todo</h2>
</div>
<div class="modal-body">
<textarea name="" class="editTextArea" id="editTodo" rows="10"></textarea>
<button class="button" id="submitEditTodo">Edit Todo</button>
</div>
<div class="modal-footer">
<!-- <h3>Modal Footer</h3> -->
</div>
</div>
</div>
<!-- End modal -->
</body>
</html>
I want to know how to make it so that when the button is clicked and a new input is added, it does not take the place of the old one, but appears in a new bix leaving the old one.
<!DOCTYPE html>
<html>
<body>
<div id="itemcreator" class="itm">
<form id="form1">
<!--where the user inputs the item-->
Item: <input name="item" type="text" size="20">
</form>
<button onclick="outputname()">Add</button>
</div>
<div class="box" id="duplicater">
<p id="output"></p>
</div>
<script type="text/javascript">
var i = 0;
var original = document.getElementById('duplicater');
duplication function
function duplicate() {
i = i + 1;
var clone = original.cloneNode(true);
clone.id = "duplicetor" + ++i;
original.parentNode.appendChild(clone);
}
function to output the item.
function outputname() {
var x=document.getElementById("form1") ;
item = x.elements.namedItem("item").value;
if (item !== ""){
document.getElementById("output").innerHTML=item;
duplicater.style.display = "block";
document.getElementById("addTrade").style.left = "7px";
itemMkrWindow.style.display = "none";
}
}
</script>
.box {
display: none;
border-radius: 5px;
border-width: 1px;
border-color: black;
border-style: solid;
}
Cant Get What you are trying to do, but maybe this will help:
var i = 0;
var original = document.getElementById('duplicater');
function duplicate() {
i = i + 1;
var clone = original.cloneNode(true);
clone.id = "duplicetor" + ++i;
original.parentNode.appendChild(clone);
}
function outputname() {
var x=document.getElementById("form1") ;
item = x.elements.namedItem("item").value;
if (item !== ""){
var createdItem = document.createElement('P');
createdItem.setAttribute('id', 'output');
var text = document.createTextNode(item);
createdItem.appendChild(text);
var container = document.getElementById("duplicater");
container.appendChild(createdItem);
}
}
this would be CSS:
.box {
border-radius: 5px;
border-width: 1px;
border-color: black;
border-style: solid;
}
#output{
display: block;
background-color: red;
width: 100px;
height: 50px;
}
check this link also
I am following the excellent example I found here: CSS - How to Style a Selected Radio Buttons Label? trying to style a group of radio-buttons which I create dynamically using javascript. While I manage to create the buttons, I can't find a solution on how to change the background of the label of the radio button that is currently selected. In my example the color only changes during hovering but flips back to normal besides being selected.
My code on JSFiddle: https://jsfiddle.net/dsarh65p/2/
For reference:
HTML
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="btn-group" data-toggle="buttons">
<span id=car></span>
</div>
</body>
</html>
JS
var array = ["Saab", "Volvo", "BMW"];
var item = document.createElement('div');
item.className = 'radio-toolbar';
for (var i = 0; i < array.length; i++) {
var input = document.createElement('input');
var input_label = document.createElement('label');
input.type = 'radio';
input.name = 'radio-btn';
input.id = 'radio' + i;
input.value = "true";
input_label.innerHTML = array[i];
input_label.setAttribute("class", "btn btn-primary");
input_label.appendChild(input);
item.appendChild(input_label);
document.getElementById("car").appendChild(item);
}
CSS
.radio-toolbar input[type="radio"] {
display: none;
}
.radio-toolbar label {
display: inline-block;
background-color: #ddd;
padding: 4px 11px;
font-family: Arial;
font-size: 16px;
cursor: pointer;
}
.radio-toolbar input[type="radio"]:checked {
background-color: #bbb;
}
var array = ["Saab", "Volvo", "BMW"];
var item = document.createElement('div');
item.className = 'radio-toolbar';
for (var i = 0; i < array.length; i++) {
var input = document.createElement('input');
var input_label = document.createElement('label');
input.type = 'radio';
input.name = 'radio-btn';
input.id = 'radio' + i;
input.value = "true";
input_label.innerHTML = array[i];
input_label.addEventListener('click', function(element) {
document.querySelectorAll('.radio-toolbar label').forEach((labelEl) => {
labelEl.selected = false;
labelEl.style.backgroundColor = '#ddd';
});
element.selected = true;
element.style.backgroundColor = 'red';
}.bind(this, input_label));
input_label.setAttribute("class", "btn btn-primary");
input_label.appendChild(input);
item.appendChild(input_label);
document.getElementById("car").appendChild(item);
}
.radio-toolbar input[type="radio"] {
display: none;
}
.radio-toolbar label {
display: inline-block;
background-color: #ddd;
padding: 4px 11px;
font-family: Arial;
font-size: 16px;
cursor: pointer;
}
.radio-toolbar input[type="radio"]:checked {
background-color: #bbb;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<body>
<div class="btn-group" data-toggle="buttons">
<span id=car></span>
</div>
</body>
Link: https://jsfiddle.net/dsarh65p/24/
EDIT:
Updated fiddle with single listener and class names:
https://jsfiddle.net/dsarh65p/26/
I have updated your fiddle here:
https://jsfiddle.net/urbandrone/y49df8wv/1/
Also, I added comments everywhere I changed your code. Basically, what you want to do is not wrap <input> elements inside a <label>, but rather next to it and connect both of them via the id attribute of the <input> and the for attribute of the <label>. This way, you can change the background color of the label with CSS only, which is almost always nicer than having to use JavaScript.
HTML
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="btn-group" data-toggle="buttons">
<span id=car></span>
</div>
</body>
</html>
CSS
.radio-toolbar input[type="radio"] {
display: none;
}
.radio-toolbar label {
display: inline-block;
background-color: #ddd;
padding: 4px 11px;
font-family: Arial;
font-size: 16px;
cursor: pointer;
}
.radio-toolbar .radio { /* style the wrapper */
position: relative; /* allows to "hide" the radio with absolute positioning (won't occupy space) */
display: inline-block; /* show wrappers in horizontal line */
}
.radio-toolbar input[type="radio"] { /* hide the <input> */
position: absolute;
z-index: -1;
}
.radio-toolbar input[type="radio"]:checked + label { /* target the <label> */
background-color: #000; /* changed to more obvious color */
}
JS
var array = ["Saab", "Volvo", "BMW"];
var item = document.createElement('div');
item.className = 'radio-toolbar';
for (var i = 0; i < array.length; i++) {
var wrapper = document.createElement('div'); // <-- create a wrapper element
var input = document.createElement('input');
var input_label = document.createElement('label');
input.type = 'radio';
input.name = 'radio-btn';
input.id = 'radio' + i;
input.checked = i === 0;
input.value = array[i]; // <-- <input>s should have different values
input_label.htmlFor = 'radio' + i; // <-- connect label to <radio> via for-attribute
input_label.innerHTML = array[i];
input_label.className = "btn btn-primary";
input_label.appendChild(input);
wrapper.className = 'radio'; // <-- add a class to the wrapper
wrapper.appendChild(input); // <-- add the <input>
wrapper.appendChild(input_label); // <-- add the <label>
item.appendChild(wrapper); // <-- add wrapper to toolbar
document.getElementById("car").appendChild(item);
}
i am doing the library project from "odin project" website and i am having trouble completing it. my idea is to access the cards particular index in the "library" array of objects, but i am having trouble doing so. my idea is to have a function that creates some type of id from its place in the array ( such as its index ) and use that as access for my delete button. any suggestions? i appreciate your time here is my codepen link
//constructor to add a book to
function Book(title, author, pages) {
this.title = title;
this.author = author;
this.pages = pages;
}
//array of books
const library = [];
//hides and unhides forms
const hide = () => {
var form = document.querySelector("#hide");
if (form.style.display === "none") {
form.style.cssText =
"display: block; display: flex; justify-content: center; margin-bottom: 150px";
} else {
form.style.display = "none";
}
};
//creates form, takes input,creates card, resets and runs hide function when done
const addBookCard = () => {
const bookName = document.querySelector('input[name="bookName"]').value;
const authorName = document.querySelector('input[name="authorName"]').value;
const numPages = document.querySelector('input[name="numPages"]').value;
library.push(new Book(bookName, authorName, numPages));
//just stating variables used within my function
const container = document.querySelector(".flex-row");
const createCard = document.createElement("div");
const divTitle = document.createElement("p");
const divAuthor = document.createElement("p");
const divPages = document.createElement("p");
const deleteBtn = document.createElement("button");
//using a class from my css file
createCard.classList.add("card");
createCard.setAttribute("id","id_num")
deleteBtn.setAttribute("onclick", "remove()")
deleteBtn.setAttribute('id','delBtn')
//geting all info from library
divTitle.textContent = "Title: " + bookName
divAuthor.textContent = "Author: " + authorName
divPages.textContent = "Number of Pages: " + numPages
deleteBtn.textContent = "Delete This Book";
//adding it all to my html
container.appendChild(createCard);
createCard.appendChild(divTitle);
createCard.appendChild(divAuthor);
createCard.appendChild(divPages);
createCard.appendChild(deleteBtn);
document.getElementById("formReset").reset();
hide()
return false
};
var btn = document.querySelector('#newCard');
btn.onclick = addBookCard;
You can change library declaration from const to let.
Then you can push books together with their corresponding deleteBtn, that way you will be able to easily remove an entry that corresponds to the clicked deleteBtn
library.push([new Book(bookName, authorName, numPages), deleteBtn]);
And then you can add event listener on deleteBtn like this
deleteBtn.addEventListener('click', event => {
event.target.parentNode.remove();
library = library.filter(v => v[1] !== event.target);
});
Where the first line removes the element from the DOM, and the second line creates new library array without the removed entry.
function Book(title, author, pages) {
this.title = title;
this.author = author;
this.pages = pages;
}
//array of books
let library = [];
//hides and unhides forms
const hide = () => {
var form = document.querySelector("#hide");
if (form.style.display === "none") {
form.style.cssText =
"display: block; display: flex; justify-content: center; margin-bottom: 150px";
} else {
form.style.display = "none";
}
};
//creates form, takes input,creates card, resets and runs hide function when done
const addBookCard = () => {
const bookName = document.querySelector('input[name="bookName"]').value;
const authorName = document.querySelector('input[name="authorName"]').value;
const numPages = document.querySelector('input[name="numPages"]').value;
//just stating variables used within my function
const container = document.querySelector(".flex-row");
const createCard = document.createElement("div");
const divTitle = document.createElement("p");
const divAuthor = document.createElement("p");
const divPages = document.createElement("p");
const deleteBtn = document.createElement("button");
library.push([new Book(bookName, authorName, numPages), deleteBtn]);
deleteBtn.addEventListener('click', event => {
event.target.parentNode.remove();
library = library.filter(v => v[1] !== event.target);
});
//using a class from my css file
createCard.classList.add("card");
createCard.setAttribute("id","id_num")
deleteBtn.setAttribute('id','delBtn')
//geting all info from library
divTitle.textContent = "Title: " + bookName
divAuthor.textContent = "Author: " + authorName
divPages.textContent = "Number of Pages: " + numPages
deleteBtn.textContent = "Delete This Book";
//adding it all to my html
container.appendChild(createCard);
createCard.appendChild(divTitle);
createCard.appendChild(divAuthor);
createCard.appendChild(divPages);
createCard.appendChild(deleteBtn);
document.getElementById("formReset").reset();
hide()
return false
};
var btn = document.querySelector('#newCard');
btn.onclick = addBookCard;
function hello (){
for (var i = 0; i < library.length ;i++) {
console.log(library[i]);
}
}
body {
margin: 0 auto;
width: 960px;
//background: cyan;
}
.flex-row {
display: flex;
flex-wrap: wrap;
}
.flex-column {
display: flex;
flex-direction: column;
}
.flex-row-form {
display: flex;
justify-content: center;
}
.flex-column-form {
display: flex;
flex-direction: column;
background: purple;
width: 45%;
padding: 20px;
border-radius: 5px;
border: 2px solid black;
color: white;
font-weight: 300;
font-size: 24px;
}
.card {
width: 33.33%;
text-align: center;
height: 200px;
border: 1px solid black;
padding: 20px;
margin: 10px;
border-radius: 10px;
}
.text {
padding-bottom: 20px;
font-weight: 300;
font-size: 20px;
}
p {
font-size: 20px;
font-weight: 400;
}
#newBook {
margin: 30px;
padding: 10px 20px;
cursor: pointer;
font-size: 16px;
color: #dff;
border-radius: 5px;
background: black;
}
#delBtn{
padding:10px;
border-radius:5px;
background:red;
color:white;
font-size:14px;
cursor: pointer;
}
<div id="display"></div>
<button id="newBook" onclick="hide()">New Book</button>
<div class="flex-row-form" id="hide" style= "display:none">
<form class="flex-column-form" id="formReset">
Book Name: <input type="text" name="bookName" value="Book Name" id="title"><br>
Author Name: <input type="text" name="authorName" value="Author Name " id="author"<br>
Number of Pages: <input type="text" name="numPages" value="# of Pages" id="pages" ><br>
<button id="newCard"> Add Book to Library</button>
</form>
</div>
<div class="flex-row">
</div>
And I have removed this line
deleteBtn.setAttribute("onclick", "remove()")
you don't need it anymore since I have added event listener for that button, and it was throwing an error because you didn't define remove function in your code.