This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 5 years ago.
I have a page where users can add their scripts to a form and then submit them. I'm using .append() to allow users to add new scripts if required, however when a new script is added the character count for that script no longer works, even though the HTML is identical (besides IDs). Is there a way to update the DOM so it will also recognise these new divs?
Here is an exmaple:
var $scriptNumber = 2;
$('.script').keyup(charCount);
$('#new-script').click(addScript);
function charCount() {
var $chars = $(this).val().length;
$(this).siblings('.char-count').html($chars + ' Characters');
}
function addScript() {
$('#scripts').append('<div id="script-' + $scriptNumber + '-wrap" class="script-wrap"><label for="script-1">Script ' + $scriptNumber + '</label><textarea id="script-' + $scriptNumber + '" class="script" cols="40" rows="3"></textarea><span class="char-count">0 Characters</span></div>');
$scriptNumber++;
}
#scripts {
padding: 12px;
}
.script-wrap {
margin-bottom: 12px;
}
label {
font-weight: bold;
}
textarea {
width: 100%;
}
#new-script {
margin-left: 12px;
padding: 4px 12px;
background: purple;
color: white;
cursor: pointer;
}
#new-script:hover {
background: blue;
}
<div id="scripts">
<div id="script-1-wrap" class="script-wrap">
<label for="script-1">Script 1</label>
<textarea id="script-1" class="script" cols="40" rows="3"></textarea>
<span class="char-count">0 Characters</span>
</div>
</div>
<span id="new-script">New Script</span>
Change the line $('.script').keyup(charCount); to $(document).on('keyup', '.script', charCount);.
The issue is being caused because it's a dynamically created element. Because of this we need to attach the function to something present on the page at the time of loading.
Here's a working JS Fiddle example
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I want to achieve a similar effect to this how could I achieve this in HTML with CSS and javascript?
<button onclick="addTemp()">ᐱ</button>
<input id="TempBox" value="15" type="text">
<button onclick="remTemp()">ᐯ</button>
<script>
function addTemp() {
document.getElementById("TempBox").innerHTML = document.getElementById("TempBox").value + 1;
}
function remTemp() {
document.getElementById("TempBox").innerHTML = document.getElementById("TempBox").value - 1;
}
</script>
I also want to make it so that if it surpasses 28 to say MAX on the next click and if it goes below 15 to make it say MIN.
Also I don't know how to achieve that look with css, the buttons to set the temperature higher or lower can be any size, but the maximum the entire thing can be is 120px high.
Logically the javascript doesn't work as I don't know how to implement it to work :/
Thanks in advance!
P.S if needed/if you want to, use JQuery
Added the basic working functionality & styling to increase & decrease the temperature, further you can explore & try to add more functionality and try to make it yourself,
Here is the Demo for your ref:
const maxTemp=28,
minTemp =15;
let tempBox = document.getElementById("TempBox");
let tempValue= Number(tempBox.value);
function addTemp() {
if(maxTemp > tempValue){
tempValue += 1;
tempBox.value = tempValue;
}
}
function remTemp() {
if(minTemp < tempValue){
tempValue -= 1;
tempBox.value = tempValue;
}
}
.temp-selector{
height:120px;
width:80px;
background-color:#000;
position:relative;
}
button {
width:100%;
height:30px;
background-color:#000;
border:none;
color:#fff;
font-size:20px;
cursor:pointer;
}
input{
width:100%;
height:60px;
background-color:#000;
border:none;
color:#fff;
font-size:44px;
padding:0;
text-align:center;
}
.degree{
color:#fff;
position:absolute;
top:30px;
right:10px;
font-size:24px;
}
<div class="temp-selector">
<button onclick="addTemp()">ᐱ</button>
<input id="TempBox" value="20" type="text">
<span class="degree">°</span>
<button onclick="remTemp()">ᐯ</button>
</div>
First, setting the .innerHTML property of an <input> element has no effect. You should be changing the value:
document.getElementById("TempBox").value = ...
Second, since the value is a string, using the + operator will cause the result to be concatenated, not added numerically. You must first turn the value into a number, before adding (or subtracting) 1 to it:
Number(document.getElementById("TempBox").value)
Alternately:
parseInt(document.getElementById("TempBox").value)
So your addTemp() function would become:
function addTemp() {
document.getElementById("TempBox").value = Number(document.getElementById("TempBox").value) + 1;
}
You are then left with the task of adding the event handlers. Without jQuery, here is one way:
document.querySelector('button').click = addTemp;
document.querySelector('button:nth-of-type(2)').click = remTemp;
As for making it say "MAX" or "MIN" when you are at the limits, that's probably not the best UX since how does the user know what value was selected as the max or min? Also, by putting a string in a field that should hold a number, you are making it more difficult to parse and then turn into the corresponding number. It would be better to put the MIN/MAX warning outside the <input> field. Here is how I would add that logic:
function addTemp() {
document.getElementById("TempBox").value = Math.Min(28, Number(document.getElementById("TempBox").value) + 1);
if (document.getElementById("TempBox").value >= 28) {
// Alert the user that they are at the max
}
}
Use some font-awesome icons and functions to increase decrease number of degrees.
Take value from the div and then put limits of min. 15 and max. 28 limits .
Used some basic JavaScript . If you face any problem within that feel free to contact in comments .
It can work without input too and if you wanted to use input than it is just simple as Replace div tag with input tag and innerHTML with value . Then restyle according to it.
document.querySelector(".decTempUnits").addEventListener("click", decreaseUnits);
function decreaseUnits() {
var units = document.getElementsByClassName("temp")[0].innerHTML
if (units > 15) {
units--;
document.getElementsByClassName("temp")[0].innerHTML = units;
document.querySelector(".demo").innerHTML = "";
} else if (units == 15) {
document.querySelector(".demo").innerHTML = "Minimum limit reached";
}
}
document.querySelector(".incTempUnits").addEventListener("click", increaseUnits);
function increaseUnits() {
var units = document.getElementsByClassName("temp")[0].innerHTML
if (units < 28) {
units++;
document.getElementsByClassName("temp")[0].innerHTML = units;
document.querySelector(".demo").innerHTML = "";
} else if (units == 28) {
document.querySelector(".demo").innerHTML = "Maximum limit reached";
}
}
.contaitner {
user-select: none;
width: 120px;
height: 120px;
background-color: black;
color: white;
display: flex;
justify-content: center;
align-items: center;
flex-flow: column;
}
.tempContaitner {
font-size: 55px;
position: relative;
}
.degree {
position: absolute;
}
.units {
font-size: 24px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div class="contaitner">
<span class="incTempUnits units"><i class="fa fa-chevron-up"></i></span>
<div class="tempContaitner"><span class="temp">20</span><span class="degree">°</span></div>
<span class="decTempUnits units"><i class="fa fa-chevron-down"></i></span>
</div>
<div class="demo"></div>
New to es6, is there a way to append HTML using template literals `` in the DOM without overwriting what was currently posted?
I have a huge block of HTML that I need to post for a list that is being created. Where a user is able to post their input.
Every-time the task is submitted it overwrites the current submission. I need it to append underneath.
fiddle for demonstration purpose.
https://jsfiddle.net/uw1o5hyr/5/
<div class = main-content>
<form class ='new-items-create'>
<label>Name:</label><input placeholder=" A Name" id="name">
<button class = "subBtn">Submit</button>
</form>
</div>
<span class="new-name"></span>
JavaScript
form.addEventListener('submit',addItem);
function addItem(event){
event.preventDefault();
let htmlStuff =
`
<div class="main">
<div class="a name">
<span>${name.value}</span>
</div>
<div>
`
itemCreated.innerHTML = htmlStuff;
}
insertAdjacentHTML() adds htmlString in 4 positions see demo. Unlike .innerHTML it never rerenders and destroys the original HTML and references. The only thing .innerHTML does that insertAdjacentHTML() can't is to read HTML. Note: assignment by .innerHTML always destroys everything even when using += operator. See this post
const sec = document.querySelector('section');
sec.insertAdjacentHTML('beforebegin', `<div class='front-element'>Front of Element</div>`)
sec.insertAdjacentHTML('afterbegin', `<div class='before-content'>Before Content</div>`)
sec.insertAdjacentHTML('beforeend', `<div class='after-content'>After Content</div>`)
sec.insertAdjacentHTML('afterend', `<div class='behind-element'>Behind Element</div>`)
* {
outline: 1px solid #000;
}
section {
margin: 20px;
font-size: 1.5rem;
text-align: center;
}
div {
outline-width: 3px;
outline-style: dashed;
height: 50px;
font-size: 1rem;
text-align: center;
}
.front-element {
outline-color: gold;
}
.before-content {
outline-color: blue;
}
.after-content {
outline-color: green;
}
.behind-element {
outline-color: red;
}
<section>CONTENT OF SECTION</section>
You can just use += to append:
document.getElementById('div').innerHTML += 'World';
<div id="div">
Hello
</div>
Element.prototype.appendTemplate = function (html) {
this.insertAdjacentHTML('beforeend', html);
return this.lastChild;
};
If you create the element prototype as per above, you can get the element back as reference so you can continue modifying it:
for (var sectionData of data) {
var section = target.appendTemplate(`<div><h2>${sectionData.hdr}</h2></div>`);
for (var query of sectionData.qs) {
section.appendTemplate(`<div>${query.q}</div>`);
}
}
Depending on how much you're doing, maybe you'd be better off with a templating engine, but this could get you pretty far without the weight.
I have done the following code in php so that I can click on the arrow and a form opens below
echo '<div class="editor" id="'.$par_code.'" style=" background-color: #fdfdfd; padding:14px 25px 30px 20px; font-family: Lucida Console, Monaco, monospace; box-shadow: 0 1px 10px 2px rgba(0,0,0,0.2),0 8px 20px 0 rgba(0,0,0,0.03); border-radius: 3px;">'
.'<img width="50" height="50" style="border-radius:50%" src="images/default.png" alt="Image cannot be displayed"/>'
.'<p class="uname"> '.$uname.'</p> '
.'<p class="time">'.$date.'</p>'
.'<p class="comment-text" style="word-break: break-all;">'.$content.'</p>'
.'<a class="link-reply al" id="reply" name="'.$par_code.'" style="padding-top: 18px; float: right;"><i class="fa fa-reply fa-lg" title="Reply"></i></a>';
My javascript code:
$(document).ready(function() {
$("a#reply").one("click" , function() {
var comCode = $(this).attr("name");
var parent = $(this).parent();
var str1 = "new-reply";
var str2 = "tog";
var res = str1.concat(i);
var tes = str2.concat(i);
// Create a new editor inside the <div id="editor">, setting its value to html
parent.append("<br /><center><form action='index.php' method='post' id='"+tes+"'><input class='iptext2' type='text' name='uname2' id='uname2' placeholder='Your Name' required /><div style='padding-bottom:5px'></div><textarea class='ckeditor' name='editor' placeholder='Your Query' id='"+res+"' required></textarea><input type='hidden' name='code' value='"+comCode+"' /><br/><input type='submit' class='form-submit' id='form-reply' name='new_reply' value='Reply' /></form></center>")
CKEDITOR.replace(res);
/*
var x = document.getElementById("tes");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
*/
i++;
});
})
The following is my css code applied to the anchor tag:
.al {
font-size:11.2px;
text-transform: uppercase;
text-decoration: none;
color:#222;
cursor:pointer;
transition:ease 0.3s all;
}
.al:hover {
color:#0072bc;
}
.link-reply {
color:#767676;
}
Here the arrow icon is displayed but is not clickable
Your code fails, because your <a> elements are created dynamically, whereas the event listener is added only to the elements available when the document has loaded.
In order to get your code to work, you need to use event delegation; that is to add the event listener to a common static ancestor, such as the document or the body, that will in turn delegate it to your target elements.
The methods you can use to achieve this effect in jQuery are on and one, with the latter fitting your case better, if you are trying to attach one-time event listeners.
Code:
$(document).one("click", "a#reply", function() {
// ...
});
Use on for dynamic created events on DOM.
$(document).on("click","a#reply" , function() {
console.log('a#reply => clicked!')
});
Or
$(body).on("click","a#reply" , function() {
console.log('a#reply => clicked!')
});
I have a DOM like this, when i fill the input field and click the button i need to create a textarea element and and stored the input value there.
if i click multiple times create multiple textarea and multiple ID's, How can i do this please check my code, Best answers must be appreciated
$('#note').on('click', function(){
var storedNoteVal = $('#enterVal').val();
var count_id = 1;
var noteCov = $('.note_cover');
$('#content_bag').prepend('<div class="full-width note_cover" id="noteId"><textarea></textarea></div>');
$(noteCov).find('textarea').val(storedNoteVal);
$(noteCov).each(function(index, element) {
$(this).attr('id', 'noteId' + count_id);
count_id++;
});
});
.full-width.note_cover {
float: left;
margin-bottom:15px;
}
.note_cover textarea {
height: auto !important;
height: 45px !important;
resize: none;
width: 100%;
/*border:none;*/
}
<div class="col-md-11 col-md-offset-1 col-sm-8 col-xs-12 mtp" id="content_bag">
</div><!-- #content_bag -->
<input type="text" placeholder="Enter project Tags" class="majorInp" id="enterVal" />
<button id="note">click me</button>
Your code is working fine, just put storedNoteVal in text-area, and input won't generate any text-area if its blank.
$('#note').on('click', function() {
var storedNoteVal = $('#enterVal').val();
var count_id = 1;
var noteCov = $('.note_cover');
if(storedNoteVal){
$('#content_bag').prepend('<div class="full-width note_cover" id="noteId"><textarea>' + storedNoteVal + '</textarea></div>');
//$(noteCov).find('textarea').val(storedNoteVal);
$(noteCov).each(function(index, element) {
$(this).attr('id', 'noteId' + count_id);
count_id++;
});
}
});
.full-width.note_cover {
float: left;
margin-bottom: 15px;
}
.note_cover textarea {
height: auto !important;
height: 45px !important;
resize: none;
width: 100%;
/*border:none;*/
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class="col-md-11 col-md-offset-1 col-sm-8 col-xs-12 mtp" id="content_bag">
</div>
<!-- #content_bag -->
<div>
<input type="text" placeholder="Enter project Tags" class="majorInp" id="enterVal" />
<button id="note">click me</button>
</div>
Building on Abhinshek answer -
Your code actually reassign id's to the textareas, since you loop through all the elements after prepending them.
You could define count_id as a window variable (outside the click function) and then just use it.
Also, you don't need to wrap noteCov with $() since $('.note_cover') returns a jQuery objects array
var count_id = 1;
$('#note').on('click', function() {
var storedNoteVal = $('#enterVal').val();
$('#content_bag').prepend('<div class="full-width note_cover" id="noteId_'+count_id+'"><textarea>' + storedNoteVal + '</textarea></div>');
count_id++;
});
This way each textarea gets it's own unique id that doesn't change
I Have a custom designed grid:
http://jsfiddle.net/97n4K/
when you click a grid item the content div of that item slides open and when you click it again it closes. This works fine.
My problem is i only ever want one content area to open at a time much like a standard accordion.
So for instance i click 'content one' - it opens 'content area one' - now if i click 'content two' i want 'content area one' to close (slideUp) and 'content area two' to open (slideDown) at the same time - just like an accordion does.
Obviously my html is alot different from a standard accordion setup so im stuggling to figure it out how to do it with my limited Jquery knowledge.
Please see my Js Fiddle above - and heres the code if you prefer below:
Thanks
HTML
<div style="width: 100%; height: 68px;">
<div class="expBtn exBlue ex1"><h3>Content<br>one</h3></div>
<div class="expBtn exOlive ex2"><h3>Content<br>two</h3></div>
<div class="expBtn exOrange ex3"><h3>Content<br>three</h3></div>
</div>
<div class="expArea expArea1">
This is content one
</div>
<div class="expArea expArea2">
This is content two
</div>
<div class="expArea expArea3">
This is content three
</div>
CSS
.expBtn {
width: 190px;
height: 68px;
text-decoration: none;
background-color: #000;
float: left;
cursor: pointer;
}
.expBtn h3 {
font-size: 18px;
font-weight: bold;
color: #e8e7e4;
text-transform: none;
line-height: 1.2em;
letter-spacing: 0em;
padding-top: 13px;
padding-left: 13px;
padding-right: 13px;
padding-bottom: 0;
font-family: arial;
margin: 0;
}
.expArea {
display: none;
width: 570px;
background-color: #ccc;
height: 200px;
}
JS
$(".ex1").click(function () {
$(".expArea1").slideToggle(1000);
});
$(".ex2").click(function () {
$(".expArea2").slideToggle(1000);
});
$(".ex3").click(function () {
$(".expArea3").slideToggle(1000);
});
$(".exBlue").hover(function () {
$(this).css("background-color","#0092d2");
}, function() {
$(this).css("background-color","#000");
});
$(".exOlive").hover(function () {
$(this).css("background-color","#9bad2a");
}, function() {
$(this).css("background-color","#000");
});
$(".exOrange").hover(function () {
$(this).css("background-color","#ff8a0c");
}, function() {
$(this).css("background-color","#000");
});
Ok so i have created essentially what i want but i have a massive load of duplicate JS that i know could be simplified by any one with better knowledge of jquery / javascript than me. Please check out this new JS fiddle - any solution to get the JS down would be greatly appreiated!
Thanks
NEW JS FIDDLE
http://jsfiddle.net/97n4K/9/
If you wish to keep your same html structure you can use the following to get what you want;
JS FIDDLE DEMO
Switch your JS click handling to this;
$('.expBtn').on('click', function () {
var area = $(this).index() + 1;
var new_div = $('.expArea' + area);
// do nothing if it's already visible
if (!new_div.is(':visible'))
{
// slide up all first
$('.expArea').slideUp(300);
new_div.slideDown(1000);
}
});
You can easily add more html sections providing you follow the same numbering you've already done.
You can use slideUp or slideDown? Im not 100% sure as to what exactly you want to achieve but this fiddle should help you.
$(".ex1").click(function () {
$(".expArea1").slideToggle(1000);
$(".expArea2").slideUp(1000);
$(".expArea3").slideUp(1000);
});
$(".ex2").click(function () {
$(".expArea2").slideToggle(1000);
$(".expArea1").slideUp(1000);
$(".expArea3").slideUp(1000);
});
$(".ex3").click(function () {
$(".expArea3").slideToggle(1000);
$(".expArea2").slideUp(1000);
$(".expArea1").slideUp(1000);
});
http://jsfiddle.net/97n4K/5/
Basically you can use a plugin for this and it will help better
I have added some simple code so your code can work
<div style="width: 100%; height: 68px;">
<div class="expBtn exBlue ex1" data-accord = "expArea1"><h3>Broadcast + Arts + Media</h3></div>
<div class="expBtn exOlive ex2" data-accord = "expArea2"><h3>Business<br>Services</h3></div>
<div class="expBtn exOrange ex3" data-accord = "expArea3"><h3>Charity +<br>NFP</h3></div>
</div>
<div class="expArea expArea1">
expArea1 content
</div>
<div class="expArea expArea2">
expArea2 content
</div>
<div class="expArea expArea3">
expArea3 content
</div>
Please look at data-accord and it's content
Now for the JS
$('.expBtn').click(function(){
var current = $(this).data('accord');
$('.expArea').each(function(){
if($(this).not('.'+current).css('display') == "block")
{
$(this).slideToggle();
}
});
$('.'+current).slideToggle(1000);
});
$(".exBlue").hover(function () {
$(this).css("background-color","#0092d2");
}, function() {
$(this).css("background-color","#000");
});
$(".exOlive").hover(function () {
$(this).css("background-color","#9bad2a");
}, function() {
$(this).css("background-color","#000");
});
$(".exOrange").hover(function () {
$(this).css("background-color","#ff8a0c");
}, function() {
$(this).css("background-color","#000");
});
You can see it working
http://jsfiddle.net/97n4K/6/
I hope this can help