This should be a very simple problem. I have an input and a button. My target is, when I click that button, a clone of that input element will appear. What I can't fix is, when I click the button, the cloned element appears only after the original element, but it should appear right at the bottom of all the cloned elements.
$(document).ready(function () {
//addition buttons handler
$(".btn-add").on("click", function () {
var id = $(this).attr("id");
var operation = id.split('-')[0].replace(/(?:^)\w/g, function (match) {
return match.toUpperCase();
});
//$("#" + operation).first().clone().val("").insertAfter("#" + operation + ":last");
//$("#" + operation + ":last").after($("#" + operation).first().clone().val(""));
$("#" + operation).last().after($("#" + operation).first().clone().val(""));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input class="form-control" id="BccList" name="BccList" type="text" value="">
<button type="button" id="bccList-add" class="btn btn-primary btn-add">+</button>
What am I missing here?
TL;DR
Use class rather than id for this.
Details
id values must be unique on the page. When you break that rule, browsers are free to do whatever they want with the subsequent elements. The consensus seems to be that they leave the id on subsequent elements using it, but don't rely on that.
If they do (leave the id on subsequent elements), $("#the-id") returns a jQuery object wrapping only the first one:
console.log($("#the-id").length); // 1
<div id="the-id"></div>
<div id="the-id"></div>
<div id="the-id"></div>
<div id="the-id"></div>
<div id="the-id"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
(But don't rely on that, either, because it's not true with more complex selectors.)
Related
I'm trying to select an element using a variable in the selector to remove the nearest element with class flag-container. However, the element isn't removed when I trigger the function.
function remove_div() {
let comment_pk = 1
$("div:contains('" + comment_pk + "')").closest('.flag-container').remove()
}
$('#trigger').click(function() {
remove_div()
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div hidden class="comment-pk">1</div>
<div class="drilled-hierarchy">
<div class="flag-container">
To be removed
</div>
</div>
<button id="trigger"> Remove </button>
The issue in your logic is that closest() travels up the DOM along ancestor elements. The .flag-container you're looking to target is instead a child of a sibling to the original div.
Therefore you can use next()* and find() instead:
function remove_div() {
let comment_pk = 1
$("div:contains('" + comment_pk + "')").next('.drilled-hierarchy').find('.flag-container').remove()
}
$('#trigger').click(function() {
remove_div()
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div hidden class="comment-pk">1</div>
<div class="drilled-hierarchy">
<div class="flag-container">
To be removed
</div>
</div>
<button id="trigger">Remove</button>
*using a selector string argument in the next() call is optional in this case, but saves unexpected bugs later. siblings() may also be appropriate depending on your exact use case.
In vanilla JS, will only find exact matches:
[...document.querySelectorAll('div')]
.find(d=>d.textContent===String(comment_pk))
.nextElementSibling
.querySelector('.flag-container')
.remove();
So I more than one dynamicly generated elements with the same class name that I am trying to check input for in jQuery. Instead of it letting me click on both, it is just letting me click the first element generated.
Ex: I click on item_1 and it returns the item_1 id, but when I click on item_2 it doesn't return anyting.
HTML
<div id="item_1" class="resp"></div>
<div id="item_2" class="resp"></div>
JS - Jquery
$(".resp").on("click",() =>{
var id = $(".resp").attr("id");
console.log('attempting toggle' + id);
});
Firstly, you have to use normal function instead of arrow function (to avoid missing the context). Secondly - use this keyword to refer to the actually clicked element.
$(".resp").on("click", function() {
console.log('attempting toggle ' + this.id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="item_1" class="resp">A</div>
<div id="item_2" class="resp">B</div>
This is because .attr('id') returns the value of the id attribute of the first matched element in the set.
Instead, use an old school function for the handler so the this value is equal to the clicked div, then get its id:
$(".resp").on("click", function() {
var id = $(this).attr('id');
console.log('attempting toggle ' + id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="item_1" class="resp">First</div>
<div id="item_2" class="resp">Second</div>
What you're doing here is referencing the classname to obtain the id. This gathers the id of the first classname, which isn't what you desire. What you need to do is use the this keyword to correctly obtain the id.
After removing the arrow function and changing the internal code a bit, it should look like this:
$(".resp").on("click", function() {
var id = this.id;
console.log('attempting toggle: ' + id);
});
Also make sure you've correctly installed JQuery. Pick up your JQuery embed code from here.
Also remember to include your JQuery code before your JavaScript code.
I got a question, what I have already solved, but it's just so annoying.
I have a js code, which is putting down some html code when a button is pushed with "append", and with that code I'm giving an id to an x button, and an id to the container element. I wanted to use these id-s to identify them with a click function, to remove the html code:
var num = 0;
$('.button').click(funcion(){
num++;
var code = '\
<div class="container" id="text' + num + '">\
<div id="x' + num + '">\
x\
</div>\
Some stuff\
</div>\
';
$('.puthere').append(code);
$('#x' + num).click(function(){
$('#text' + num).remove();
});
});
Now the annoying part is the click function on the x. What I would expect is, that this code would work somehow like this:
1st click on the "button" class element should give this code:
$('#x1').click(function(){
$('#text1').remove();
});
after 2nd click I should have this:
$('#x1').click(function(){
$('#text1').remove();
});
$('#x2').click(function(){
$('#text2').remove();
});
instead what I'm getting after the 2nd click is this:
$('#x1').click(function(){
$('#text2').remove();
});
$('#x2').click(function(){
$('#text2').remove();
});
so it's always the last element what the x buttons want to remove. My question is, why can my "num" variable stay "1" at the #x1, but not at the #text1?
My solution was to address the parent element instead:
$('#x' + num).click(function(){
$(this).parent('.container').remove();
});
I know, that there is the "live" function too, what I could use, and I wouldn't need to mess with id-s, but that just seems more heavy. Is that correct? Or I'm overcomplicating things too much without making it more efficent?
It's because num is global and you access it after you create second button. To fix this you can wrap your code with anonymouse self executing function:
(function(num) {
$('#x' + num).click(function(){
$('#text' + num).remove();
});
})(num);
or better use only one click
$('.parent').on('click', '.container > div', function() {
$(this).parent().remove();
});
By clicking Create I want to give continuing class name: For example now if you click Create button, it should create the following <div class="div_3">Div 3</div>:
<div id="container">
<div class="div_1">Div 1</div>
<div class="div_2">Div 2</div>
</div>
<input type="button" onclick="add()" value="Create"/>
Here is JS
function add(){
$("#container").append("<div>Div 3</div>")
}
https://jsfiddle.net/5gmr5j8z/
One way is to count the existing elements (and add 1):
$("#container").append("<div>Div " + ($("#container div").length+1) + "</div>");
Simple JSFiddle: https://jsfiddle.net/TrueBlueAussie/5gmr5j8z/2/
You need to apply the same to the class, but this gets a little messy, so neater version below.
You are also better off using jQuery to connect events. Inline event handlers do not have the power of jQuery handlers (and separate event registration from the event handler for no good reason):
$('#add').click(function () {
var count = $("#container div").length + 1;
var $div = $("<div>", {
class: "div_" + count,
text: "Div " + count
});
$("#container").append($div);
});
JSFiddle: https://jsfiddle.net/TrueBlueAussie/5gmr5j8z/3/
There are usually neater ways to do this sort of thing, but you need to explain the overall aim first
I have an issue where I have nested divs with the same class. For instance I have something like Panel, inside of Panel. However, when I click on the panel inside the first panel, it is the first panel that triggers the
$(".panel").click
function. However, I need to somehow drill down to the panel which the mouse actually clicked on. In other words if I had the following code:
<div class="panel"> //first panel
<div class="panel"> //second panel
</div>
</div>
When I want the second panel to trigger the click, I instead get the parent panel triggering the click. This makes sense given the second panel is wrapped in the first panel. However, I was wondering if there is a way around this? In theory, the code that I am writing can have an infinite ammount of panels inside of other panels. Is there a way to drill all the way down to the panel that the mouse has clicked on? (not the containing panel)
EDIT:
Here is the entire code segment:
<style type="text/css">
body
{
height: 700px;
}
.gridSegment
{
width: 50%;
height: 50%;
float: left;
outline: 2px solid black;
}
</style>
<script type="text/javascript">
$(document).ready(function(){
var lastID = 10;
$(".gridSegment").dblclick(function(){
console.log($(this).attr("ID"));
lastID++;
$(this).append("<div class='gridSegment' id='" + lastID + "'></div>");
lastID++;
$(this).append("<div class='gridSegment' id='" + lastID + "'></div>");
lastID++;
$(this).append("<div class='gridSegment' id='" + lastID + "'></div>");
lastID++;
$(this).append("<div class='gridSegment' id='" + lastID + "'></div>");
return false;
});
});
</script>
</head>
<body>
<div class='gridSegment'>
<div class='gridSegment' id ="1"></div>
<div class='gridSegment' id ="2"></div>
<div class='gridSegment' id ="3"></div>
<div class='gridSegment' id ="4"></div>
</div>
</body>
Check out this example on jsFiddle (open your JavaScript console)
(please excuse the ugly colors - I'm a programmer not a designer ;).
$(function(){
$('.panel').on('click',function(e){
console.log($(this));
return false;
});
});
All you have to do is return false when you capture the click to stop the event bubbling back up to the containing element.
I've taken the liberty of changing your code slightly (just for the example). Mainly the loops and I also changed the id attributes to add a little more information - you can now see exactly what level you are in. If you feel it suites your needs then by all means you can adopt it into your application.
You mentioned in a comment that the .live() function solves your problem, however this feature is deprecated as of jQuery 1.7 and it is recommended to use the delegate() function in place of live() if you can't use on(). So here is my solution using the delegate() function.
As you can see the syntax is similar only that we attach the callback to the container element and specify what internal selector to use - in our case it is any .gridSegment element.
$("#body").delegate(".gridSegment", "dblclick", function() {
var $thisCached = $(this);
console.log($thisCached,$(this).parent());
var lastId = $thisCached.attr("id");
var limit = 4;
var counter = 1;
while(counter <= limit){
var newId = lastId + '_' + counter;
counter++;
$thisCached.append("<div class='gridSegment' id='" + newId + "'></div>");
}
return false;
});
Note that my wrapper is an element with the id of body
jsFiddle example
Use id's
<div class="panel" id="panel_1">
<div class="panel" id="panel_2">
...
or use data-* attributes
<div class=panel data-pid=1>
then
$('.panel').click(function(){
alert('panel id is: '+$(this).attr('data-pid'));
})