I'm working on something that creates a form based on choices you give it (text/textfield/dropdown). When I create 2 dropdowns at once I am not sure how to write in a way that the computer can tell the 2 elements aren't the same, specifically when adding new inputs in my dropdown creator it can't tell multiple dropdowns apart.
Here's the Javascript function I'm using for it
$('#submit').on('click', function() {
$("select").each(function() {
switch($(this).val()) {
case "text":
$("#form").append('<p><input type="text"/> <button class="remInput">Remove</button></p>');
break;
case "note":
$("#form").append('<p><textarea></textarea> <button class="remInput">Remove</button></p> ');
break;
case "dd":
$("#form").append('<p><select id="ddFinal"><option></option></select> <button class="remInput">Remove</button></p>');
$("#ddCreator").append('<button id="ddAddInput">Add Another Field</button> <p class="ddP"><input type="text" name="ddText"/></p> <button id="ddSubmit">Submit</button>');
break;
}
});
$('#inputDiv').empty();
$('#ddAddInput').on('click', function() {
$("p[class*='ddP']").append('<input type="text" name="ddText"/>');
});
$('#ddSubmit').on('click', function() {
$("input[name*='ddText']").each(function() {
$('#ddFinal').append('<option>'+$(this).val()+'</option>');
});
$('#ddCreator').empty();
$('#ddFinal').removeAttr('id');
});
});
The problem is with the ddAddInput function because it doesn't specify between multiple p class="ddp" elements but I'm not really sure what I should be putting instead. Hope this question makes sense.
Here's the fiddle I'm currently working on http://jsfiddle.net/me74Z/15/
There are several flaws in approach that need to be remedied.
First: - element Id's are unique in a page by definition. Use classes instead.
Next, your event handlers are being added from within another event handler. If you were to change all the ID's you have to classes and the corresponding selectors in the event handlers, you would end up compounding events.
What compounding events means is if you add the same handler twice to an element, it will fire twice.
Using event delegation would be easier. Set up your event delegation outside of the current click handler for #submit
$(document).on('click', '.ddSubmit', function() {....});
Now, as for how to handle instances, within every event handler this is the element that is the target of the event.
Using $(this) and jQuery traverse methods you can work with the target's parent and siblings or whatever you need to do.
I would suggest you wrap each level in a container to simplify the traversals. I'll call container class row so that a generic traverse from an event target can look something like:
var someField= $(this).closest('.row').find('.someField');
WHen remove button is clicked, simply remove the parent row
Related
I have to add a list of checkboxes dynamically. I then need to know which one performed the click, then ask if it's checked or not.
I have this code:
$('#MyContainerOfChecksDiv').click( '.MySelectorClass', function(){
if ("MyCheckClicked".is(':checked'))
{
//...here i need to use the label and id
}
else{...}
})
using "$(this)" i get the "MyDiv", obviously using $(this).find('input:checkbox') I get the whole list of checks.
I have to get this checkbox because I need to use its properties.
Add a formal parameter to click handler and use it like this
$('#myDiv').click('.MySelectorClass', function (e) {
if ($(e.target).is(':checked')) {
alert(e.target.id);
}
})
fiddle
Also it's not quite clear to me how you distinguish dynamically added elements and static. Do you have different class for them? If so then you dynamic and static elements can have different handlers and this will be the way to tell whether it was created dynamically
To delegate to dynamic elements you have to use .on(). The element that you clicked on will be in this.
$("#myDiv").on("click", ".MySelectorClass", function() {
if (this.clicked) {
// here you can use this.id
} else {
// ...
}
});
You can't use .click() to delegate like you tried. You're just binding the click handler to the DIV, and the string ".MySelectorClass" is being passed as additional data to the handler.
so what I'm triying to achieve is that I want one element to append some other elements to div and change its ID attribute (or something similar).
i have tried something like this
$('#add3').click(function(){
$('#add3').attr("id", "add4");
$('.third_row1').append('something to append');
});
and also tried something like this:
$('#add').click(function(){
var vari = $("<div id='add2'>add another user</div>");
$('#add').remove();
$('.third_row1').append(vari);
$('.third_row1').append('something to append');
});
so clicking one button (like second example) has no effect on third, fourth ... n click
same thing with the second example
thanks in advance for help
UPD
ok, so here's how I generate selects which I want to append
<jsp:useBean id="obj1" class="com.Users" scope="page"/>
<div class="third_row1">
<select name="mySelect1" id="mySelect1">
<c:forEach var="item1" items="${obj1.items}">
<option>${item1}</option>
</c:forEach>
</select>
</div>
all I want to do is to add same select, but with different ids and names
Since elements IDs are changed dynamically, you should use delegated event handlers with .on().
For example:
$(document).on("click", "#add3", function() {
$('#add3').attr("id", "add4");
$('.third_row1').append('something to append');
});
If all these elements (#add, #add3) are inside page static element, it will be better to use this element instead of document for perfomance:
$("static_element_selector").on("click", "#add3", function() {
And just to note: since this inside event handler points to clicked DOM element, you can use this.id = "add4" instead of $('#add3').attr("id", "add4");. It is shorter and works slightly faster.
This question is connected with that
This code hides div when user type data to inputs and focus on another div
$(".Q,.A").blur(function(e) {
if ($(this).val().length > 0 && $(this).siblings("input").val().length > 0) {
$(this).parent().fadeOut(1000);
getData("ajaxPHP/insertNewWords.php?q='" + $(this).siblings('input').val() + "'&a='" + $(this).val() + "'&zestawID="+zestawID, "console");
$(".main").append("<div><input type='text' class='Q'></input><input type='text' class='A'></input></div><br>");
}
});
And when user enter data, this div hides and script creates new div (so user can enter infinite amount of data).
The problem is: new created divs don't hide.
So what should I do, if I want to involve new created divs into "$(".Q,.A")"?
The problem is (as I understand it), that you have a behaviour attached to a set of nodes on your page, and new nodes added to the page do not pick up this behaviour.
This is because of the way JQuery works. When you define a selector like $(".Q,.A") this selector evaluates to a set of known nodes on your page. The code that follows only applies to those found elements. This selector is never evaluated again, so any new nodes never get a chance to gain your desired behaviour.
The solution is to get JQuery to re-evaluate the selector every time the event occurs. So you need to listen for the event globally, then filter to only handle the elements that match your selector.
The correct way to do this is on
$(document).on("blur", ".Q,.A", function(){ ... });
See: http://jsfiddle.net/sAT6L/
Live has some discussion on how it used to be done in each version of JQuery.
Note: You should be able to restrict the scope to something more local than $(document).
You can use jquery's .on method on the parent container, because events "bubble" to the parent container. The on function also allows you to specify a selector to filter the children elements, which gets applied dynamically, so you can use your ".Q,.A" selector there:
$(document).ready(function(){
$("#container").on("blur", ".Q,.A", function(e){
if($(this).val().length>0 && $(this).siblings("input").val().length>0){
$(this).parent().fadeOut(1000);
$("#container").append('<div><input type="text" class="Q"><input type="text" class="A"></div>');
}
});
});
Fiddle: http://jsfiddle.net/rK3HS/1/
After html is entered into a container from a ajax response I would like to bind an event to various elements. I know this can be achieved by running addEventListener or on+event=function(){} right after the html is inserted.
My problem is that I am unsure of the best method to do so with dynamic content, whereas the data passed into the event is different each time.
For example, the following html is loaded into a container:
<button id="myButton">go</button>
Now, I need to bind an onclick function to the button element that contains data that was rendered on the remote side - the onclick function would be something like:
myFunction($data1,$data2,$data3);
whereas $data1,$data2,$data3 are variables with the dynamic data.
One way I can have this function bound to the button is by outputting a script to be evaluated after the HTML data is inserted into the container, so the HTML output would go like this:
<button id="myButton">go</button>
<script>document.getElementById('myButton').addEventListener('click',function(){myFunction(<?php echo $data1.','.$data2.','.$data3 ?>)});})</script>
Is there anyway I can achieve the result from the above code in a more flexible way without having to output that script line for every element and for each request?
A way that I thought of is to have a bind function that is called after every request is completed, and in this function every element that needs an event bound is stored in an array. A loop goes through the array and binds the appropriate event and function - but this gets complicated with dynamic data. Any ideas?
Use your own form of event delegation:
var container = document.getElementById("container");
container.addEventListener("click", function (e) {
e = e || window.event;
var target = e.target || e.srcElement;
if (target.tagName === "BUTTON") {
// execute handler code for buttons
}
}, false);
Where the container element is the closest, stable (not being added/removed from the DOM) element that these dynamic elements/buttons are being added to at some level.
The event is bound once to one containing element, but is triggered for any click event that bubbles up from descendants (the default behavior of click events).
This will simply check if the tagName of the element is "button". This is pretty broad, but if this is the thing you want to filter out, that's what you can use. If you want to use a class, add a specific class (maybe "special-class") to the dynamic buttons and use:
if (~(" " + target.className + " ").indexOf(" special-class ")) {
// execute handler for buttons with class "special-class"
}
If you need to pass specific data with the buttons/elements, add a specific data-* attribute that contains it, to the buttons when generating them:
<button id="whateverId" data-data1="$data1" data-data2="$data2" data-data3="$data3">go</button>
And in the event handler where you know it's the targeted buttons, you can use:
var data1 = target.getAttribute("data-data1");
var data2 = target.getAttribute("data-data2");
var data3 = target.getAttribute("data-data3");
Reference:
http://webdesign.tutsplus.com/tutorials/htmlcss-tutorials/all-you-need-to-know-about-the-html5-data-attribute/
http://caniuse.com/dataset
I have created a label element. I need to add onclick event to that...
function a(me) {
var d=document.createElement("label");
d.id=me.id;
d.onClick="a(10)";
d.innerHTML="welcome";
document.body.appendChild(d);
}
HTML:
<label id="1" onclick="a(this)">aa</label>
<label id="2" onclick="a(this)">bb</label>
<label id="3" onclick="a(this)">aa</label>
actually what happens is when i click the any of three labels in html. another label is created and displays welcome. now when i click the newly created label "welcome" it does not display anything...... that is the onclick event added to newly created label is not working ....... any suggestion.................
You need to set d.onclick=function(){a(1);};, note that the case matters here (not "onClick").
[Edit]
Based on your comments and updated questions I've created a jsFiddle to demonstrate how you might turn your code into something that works.
d.setAttribute('onclick', 'alert(\'hello\');');
For creating an attribute to a HTML tag, sometimes we have to add this:
yourTag.src
yourTag.src = 'http://lolxd.com/404.png'
But there are special attributes, and them have diferents ways for editing:
yourTag.classList
yourTag.className
And there is the onclick attribute, wichwe can use it like this:
// The first way
obj.onclick = function () { alert('lalala') }
// With the Event Listener
obj.addEventListener('click', function () { alert('lalala') }, false)
// Or, a text-render way
obj.setAttribute('onclick', 'alert(`lalala`)')
I recomend you the Event Listener way, but try all :D