I have already 3 existing boxes on a page (divs) with a unique ID (1,2,3) each. I want to have a button by each one of them that allows the user to add new boxes right below. These boxes should follow the already existing numbering. However, doing this will also imply to update the IDs of the already existing boxes underneath the new ones so the numbers match.
This is my code:
function add_box(n) {
document.getElementById("box"+(n<)).setAttribute("id", "box");
var div = document.createElement("div");
div.id="box"+(n+1);
var txt = document.createTextNode("A new box");
div.appendChild(txt);
var newbox = document.getElementById("box"+n);
insertAfter(div,newbox);
}
HTML
<div id="box1">Whatever</div><input type="button" onclick="add_box(1)">
<div id="box2">Whatever</div><input type="button" onclick="add_box(2)">
<div id="box3">Whatever</div><input type="button" onclick="add_box(3)">
Its obviously not working because i guess i need to have an array with all the elements that contain "box" in the ID and then somehow update their numbers but i dont know how to do all that.
Thank you.
The following does what you ask, but I suspect it isn't the result you want.
<script>
// Append a new div after one with id boxn
function add_box(n) {
var el = document.getElementById('box' + n);
var div = document.createElement('div');
div.id = 'box' + ++n;
div.appendChild(document.createTextNode('New box ' + n));
el.parentNode.insertBefore(div, el.nextSibling);
renumberDivs(div, n);
}
// Renumber all sibling divs after el
function renumberDivs(el, n) {
// Note assignment, not equality
while (el = el.nextSibling) {
if (el.tagName && el.tagName.toLowerCase() == 'div'){
el.id = 'box' + ++n;
}
}
}
</script>
<div id="box1">Whatever</div><input type="button" value="add below 1" onclick="add_box(1)">
<div id="box2">Whatever</div><input type="button" value="add below 2" onclick="add_box(2)">
<div id="box3">Whatever</div><input type="button" value="add below 3" onclick="add_box(3)">
Note that in the above, numbers are passed as arguments that are treated as numbers but also implicitly converted to strings when used for the ID value. That sort of type conversion isn't really liked, consider using a more explicit method.
After a few clicks, you may end up with something like:
<div id="box1">Whatever</div>
<div id="box2">New box 2</div>
<div id="box3">New box 3</div>
<div id="box4">New box 4</div>
<div id="box5">New box 4</div>
<div id="box6">New box 4</div>
<div id="box7">New box 2</div><input type="button" value="add a box" onclick="add_box(1)">
<div id="box8">Whatever</div><input type="button" value="add a box" onclick="add_box(2)">
<div id="box9">Whatever</div><input type="button" value="add a box" onclick="add_box(3)">
Related
I have a box 2 x 2 using flex property with number 0 inside each box, and a button to click
function click() {
var id = "item-";;
for(var i = 1; i <= 6; i++) {
id = id + i;
var element = document.getElementById(id);
var value = element.innerHTML;
value++;
document.getElementById(id).innerHTML = value;
}
}
<div class="flex-container">
<div class="container-1">
<div id="item-1">0</div>
<div id="item-2">0</div>
<div id="item-3">0</div>
</div>
<div class="container-2">
<div id="item-4">0</div>
<div id="item-5">0</div>
<div id="item-6">0</div>
</div>
</div>
<button class="btn" onclick="click()">Click</button>
I want to create a function click() that if I click a button then the number inside the box will increase, but not all numbers in all boxes. I want the number increasing box by box.
But my function only increases the value in the first box. Can someone let me know what should I do, please?
Currently, first iteration of the for () will work because id will become item-1, but the second iteration you will create the new id, but you just append i, so it becomes item-12 instead of item-2
Just only remember the id and prefix it with item- when you use it. Then after each press, update the innerHTML and increase the counter, or reset to 1 if we've just updated the last <div>
var currentIndex = 1;
function incrementButton() {
let element = document.getElementById('item-' + currentIndex);
element.innerHTML = ++element.innerHTML;
currentIndex = (currentIndex === 6) ? 1 : ++currentIndex;
}
<div class="flex-container">
<div class="container-1">
<div id="item-1">0</div>
<div id="item-2">0</div>
<div id="item-3">0</div>
</div>
<div class="container-2">
<div id="item-4">0</div>
<div id="item-5">0</div>
<div id="item-6">0</div>
</div>
</div>
<button class="btn" onclick="incrementButton()">Click</button>
I have a div with id="add-dependent" including 2 rows and a button (add dependent) inside of the div. When "add dependent" button is clicked, the first row would be cloned and insert before (add dependent) button. Actually I have another button outside of the div called (add applicant) and by clicking it, whole of the div would be cloned and added before (add applicant) button. my code is like this :
let nextLabel=2
let nextId=1
function addApplicant(){
var elem= document.querySelector("#add-dependent");
var clone=elem.cloneNode(true);
var add= document.getElementById("add-applicant");
clone.id = "add-dependent"+nextLabel;
elem.parentElement.insertBefore(clone,add);
var label = clone.querySelector("label");
label.innerHTML = '<button class="close remove" onClick="$(this).parent().parent().parent().parent().remove()">x</button>' + "Applicant " + (nextLabel++) ;
}
function addDependent(){
var elem= document.querySelector(".dependent");
var clone=elem.cloneNode(true);
var add= document.getElementById("dependent");
elem.parentElement.insertBefore(clone,add);
var label=clone.querySelector('label');
label.innerHTML= '<button id="btn" name="btn" type="button" class="close float-left" style="font-size:12px;" onClick="$(this).parent().parent().parent().remove();" >x</button>';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="add-dependent">
<div class="form-row dependents">
<div>
<label class="text-left" contenteditable="true">Applicant 1: </label>
</div>
<div >
<input type="number" placeholder="age">
</div>
</div>
<div class="form-row dependent">
<div>
<button id="btn" name="btn" type="button" class="close " onClick="$(this).parent().parent().remove();" >x</button>
</div>
<div>
<input type="number" placeholder="age">
</div>
</div>
<button id="dependent" onClick="addDependent()">Add dependent</button>
</div>
<button id="add-applicant" onClick="addApplicant()">Add applicant</button>
my problem is when i click on (add dependent) in cloned div, the row is added to main div not cloned one.
hope to here you soon.
Thanks a lot
There are many changes I made to your code and I'll try to explain them here. When you're working with duplicating, appending, removing etc, id's can become difficult to work with - you can't have duplicates of IDs and your code then has to track which id is affected by which button etc.
Its much easier to work with relative paths. For instance when you want to add a dependent, it's easier to say 'find a dependent input to clone and place it inside the container from where I clicked this add-dependent button' - and walla no need for ids. To find the relative div's, I used a combination of event.target, closest() and querySelctor - like this:
e.target
.closest('.add-applicant-container')
.querySelector('.dependents')
.append(clone);
This says Starting from the button I clicked, find the closest '.add-applicant-container' and inside that find the first '.dependents' and place our clone right after that
Finally, the buttons. Because you're creating and destroying these buttons in the process, it's best to set up a listener on document and test to see which button was clicked. This is called event delegation. For the dependent delete button, we only need to find the relative element and delete it so:
if (e.target.classList.contains('close')) {
e.target.closest('.dependent-container').remove()
}
let nextLabel = 2
let nextId = 1
document.addEventListener('click', function(e) {
if (e.target.classList.contains('add-applicant')) {
addApplicant(e)
} else if (e.target.classList.contains('btn-dependent')) {
addDependent(e)
} else if (e.target.classList.contains('remove-applicant')) {
e.target.closest('.add-applicant-container').remove()
} else if (e.target.classList.contains('close')) {
e.target.closest('.dependent-container').remove()
}
})
function addApplicant(e) {
let applicant = document.querySelector('.add-applicant-container')
var clone = applicant.cloneNode(true);
clone.id = "add-dependent" + nextLabel;
clone.querySelectorAll('.dependent-container').forEach((el, i) => {
if (i !== 0) el.remove()
})
applicant.parentElement.insertBefore(clone, e.target);
var label = clone.querySelector("label");
label.innerHTML = '<button class="close remove-applicant">x</button>' + "Applicant " + (nextLabel++);
}
function addDependent(e) {
let dependent = document.querySelector('.dependent-container')
var clone = dependent.cloneNode(true);
e.target.closest('.add-applicant-container').querySelector('.dependents').append(clone);
// var label = clone.querySelector('label');
// label.innerHTML = '<button id="btn" name="btn" type="button" class="close float-left" style="font-size:12px;" >x</button>';
}
.add-applicant-container{
padding:10px;
}
.dependent-container{
padding:5px 0 ;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="add-applicant-container">
<div class="form-row dependents">
<div>
<label class="text-left" contenteditable="true">Applicant 1: </label>
</div>
<div>
<input type="number" placeholder="applicant age">
</div>
</div>
<div class="form-row dependent-container">
<div>
<input type="number" placeholder="dependent age"> <button id="btn" name="btn" type="button" class="close ">x</button>
</div>
</div>
<button class="btn-dependent">Add dependent</button>
</div>
<button class="add-applicant">Add applicant</button>
I'm building a wee letter-writing tool that will have a range of paragraphs the user can choose to add to a letter, but I worry that I'm doing it in a really inefficient way.
Currently, it's structured like this:
<p id="deposit-dispute" class="paragraph">This is a paragraph about deposits not being protected</p>
<button onclick="addPara(depositDispute)" class="add">Add paragraph</button>
and then in the Javascript, I create a const that pulls the inner HTML of that id:
const depositDispute = "\n" + document.getElementById("deposit-dispute").innerHTML + "\n";
which the addPara() function then adds to the textarea:
function addPara(text) {
document.getElementById("text-body").value += text;
}
But would there be a way to make the function just call whatever the previous p element had in it, rather than having to give them all unique IDs and creating a unique variable for them all?
Here it is in a codepen so you can see what I'm trying to do - the paragraphs to be added are in the accordion on the right: https://codepen.io/gordonmaloney/pen/GRWyjOP
Thanks a lot - and big apologies if this is a ridiculously amateurish question, I've spent ages trying to google a solution but can't find a thing!
G
Each box contains a paragraph and a button.
We can get all the boxes and each box paragraph and button, and finally add click event to the button to insert the paragraph html of this box to the textarea
// Get textarea and boxes
var textarea = document.getElementById('textarea');
var boxes = document.querySelectorAll('.box');
// get the button and the paragraph of each box
boxes.forEach(box => {
var btn = box.querySelector('.button');
var paragraph = box.querySelector('.paragraph');
// add the html of the selected box paragraph to the textarea
btn.addEventListener('click', () => {
textarea.value += "\n" + paragraph.innerHTML; + "\n";
});
});
<div class="wrapper">
<div class="box">
<p class="paragraph">This is paragraph 1</p>
<button class="button">Add to textarea</button>
</div>
<div class="box">
<p class="paragraph">This is paragraph 2</p>
<button class="button">Add to textarea</button>
</div>
<div class="box">
<p class="paragraph">This is paragraph 3</p>
<button class="button">Add to textarea</button>
</div>
</div>
<textarea name="" id="textarea" cols="30" rows="10"></textarea>
I have Multiple Div which contain the delete button.
Once I click the button I need to update the Id of every div below the deleted Div.
<div id="btn1" name="btn1"> Delete Button</div>
<div id="btn2" name="btn2"> Delete Button</div>
<div id="btn3" name="btn3"> Delete Button</div>
<div id="btn4" name="btn4"> Delete Button</div>
If I delete the btn2 then btn3 id should change to btn2 and btn4 id should change to btn3.
I have tried with att() function but its not working.
<div id="btn1" name="btn1"> Delete Button</div>
<div id="btn2" name="btn2"> Delete Button</div>
<div id="btn3" name="btn3"> Delete Button</div>
$('#btn' + i + '').attr('id', 'btn' + i - 1 + '')
You could do something like this:
$("[id^=btn]").click(function(){
var prevId = this.id;
$(this).nextAll("[id^=btn]").each(function(){
var tmpId = this.id;
this.id = prevId;
prevId = tmpId;
});
$(this).remove();
$("[id^=btn]").each(function(){
console.log("Name:", $(this).attr("name"), "ID:", this.id)
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="btn1" name="btn1"> Delete Button</div>
<div id="btn2" name="btn2"> Delete Button</div>
<div id="btn3" name="btn3"> Delete Button</div>
<div id="btn4" name="btn4"> Delete Button</div>
I don't really know what you're using this for but I'm sure that there are better ways of doing it.
The important part in the code above is nextAll, you can find out more about it HERE
The last part of your code, i.e. 'btn' + i - 1 + '', returns NaN. You need to put i - 1 into parentheses: (i - 1). Plus the + '' parts are unnecessary.
So you can try: $('#btn' + i).attr('id', 'btn' + (i - 1))
The answer by Titus is more comprehensive so you should probably use it – or do something completely different altogether as others have also suggested.
Number of ways to do this. Here is another that might work for you. This is more fluid.
$(".btn").click(function(e) {
var btns = [];
var $that = $(this);
$that.parent().find(".btn").each(function(ind, elem) {
if ($(elem).attr("id") != $that.attr("id")) {
btns.push($(elem));
}
});
var res = confirm("Are you sure you wish to delete this?");
if(res){
console.log("Removing " + $that.attr("id"));
$that.remove();
$.each(btns, function(key, $item) {
console.log("Re-labeling " + $item.attr("id"));
$item.attr({
id: "btn-" + (key + 1),
name: "btn-" + (key + 1)
});
console.log("New Label " + $item.attr("id"));
});
}
return false;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div id="btn-1" name="btn-1" class="btn"> Delete Button</div>
<div id="btn-2" name="btn-2" class="btn"> Delete Button</div>
<div id="btn-3" name="btn-3" class="btn"> Delete Button</div>
<div id="btn-4" name="btn-4" class="btn"> Delete Button</div>
</div>
You may also want to add a confirm() condition within the click event. I added it to my example.
You do not have to use an array. For me, it's an extra control layer. This give you an easy way to group and manage the jQuery Objects you want to manipulate. Using $.each() to then iterate over that array, you can easily re-assign the id and name based on the array index.
Using an id with "-" can also be helpful for other attribute selectors, like [name|="value"]:
Description: Selects elements that have the specified attribute with a value either equal to a given string or starting with that string followed by a hyphen (-).
See more: https://api.jquery.com/attribute-contains-prefix-selector/
So I am trying to create pop up logic for a simple find an object game. So I created a an array of strings that I want to display 2 alert messages. The first alert stating hey you found [insertName].Then if you click on the same object again it display a generic message "you already found this". Then after all images have been clicked, I have a new page loaded based of the int count of items clicked. What I'm having trouble with is how to execute that first initial alert. I was thinking I would create another array for the initial alerts,but that when i got stuck.
<div id="b1" class="mybox">One</div>
<div id="b2" class="mybox">Two </div>
<div id="b3" class="mybox">Three </div>
<div id="b4" class="mybox">Four </div>
<div id="b5" class="mybox">Effortless Calls </div>
<div id="b6" class="mybox">Voicebot </div>
<script type="text/javascript">
//$('body').css('background','blue');
var Boxes = [];
var ttle = $('.mybox').length;
$('.mybox').click(function () {
alert('Blah ');
var bx = this.id;
if (Boxes.indexOf(bx) >= 0){
alert('You Already Found Object ');
}else{
Boxes.push(bx);
}
if (Boxes.length ==ttle)
window.location = "#/finishedgame";
});
</script>
Add a custom attribute to the your elements data-clicked="false"
When the user clicks the element set elem.setAttribute('data-clicked','true');
<div id="b1" class="mybox" data-clicked="false">One</div>
<div id="b2" class="mybox" data-clicked="false">Two </div>
<div id="b3" class="mybox" data-clicked="false">Three </div>
<div id="b4" class="mybox" data-clicked="false">Four </div>
<div id="b5" class="mybox" data-clicked="false">Effortless Calls </div>
<div id="b6" class="mybox" data-clicked="false">Voicebot </div>
$('.mybox').click(function (elem) {
var clicked = $(elem).data('clicked');
if(clicked){
alert(msg1);
} else {
alert(msg1);
elem.setAttribute('data-clicked','true');
};
});
You don't need another array, before you do Boxes.push(bx); why don't you just do alert(hey you found [insertName]);? this should be the first time a user is touching a box aka when you want the first alert at least from what I gathered from your post. So
var Boxes = [];
var ttle = $('.mybox').length;
$('.mybox').click(function () {
var bx = this.id;
if (Boxes.indexOf(bx) >= 0){
alert('You Already Found Object ');
}else{
var text = [get name of box here]
alert("hey you found" + text);
Boxes.push(bx);
}
if (Boxes.length ==ttle)
window.location = "#/finishedgame";
});