Using .jquery .on() without an event - javascript

I have input elements that get appended to my HTML document that I need to get the value of. I understand that .on() should be used to get appended elements, but .on() expects an event to activate it, and I don't need an event.
Below is the code. #save_design is on a different part of the page. #fields_cnt is the parent that holds all my appended forms. .reg_field is the element I'm trying to get the value of. The first child works because that form is present when the document is loaded, or in other words, it is not appended. The other children all returns values undefined, or false depending on the input type and the logic I'm applying to it. This leads me to believe that .on() or something close to it should be used.
To clarify, I am trying to get the value of an appended input when #save_design is clicked.
$('#save_design').click( function() {
group_text[form_count] = $('#fields_cnt .field_group:nth-child(' + child + ') .reg_field').val();
I have tried replacing the originating click event as so. It has not worked.
$('body').on('click', '#save_design', function(){
I have tried using .on() without an event or event object. It has also not worked.
$('body').on('', '', function(){
group_text[form_count] = $('#fields_cnt .field_group:nth-child(' + child + ') .reg_field').val();
});
I have found a plugin that should work.
JQuery selecting dynamically generated html without adding event (with live)
This is not ideal, because as stated in the github readme, it is being rewritten. Also, the SO answer is 3 years old now, so it may no longer be the correct answer.
https://github.com/brandonaaron/livequery
I'd like to find a more direct solution. Is there a way to do this natively in jQuery? Is there a way to use .on() without an event, and if so, what's the appropriate syntax?
UPDATE: Clarification: The input fields get appended when an add field button is pressed. Their values change after they are appended. I would prefer not to rerecord the value of an input, every time it is altered.
UPDATE Here is the HTML structure to give a better idea of how I'm defining child.
<div id="fields_cnt">
<div id="field_group_1" class="field_group form-group">
<input placeholder="Field" class="reg_field form-control" />
</div>
<!-- This is appended by jQuery. There may be multiple of these -->
<div id="field_group_2" class="field_group form-group">
<input placeholder="Field" class="reg_field form-control" />
</div>
</div>

I have found a great solution to my problem. It takes a different approach on selecting the element, but ultimately works and results in drier code.
Here, I use each, to grab each instance of the appended element I am trying to select. This returns the desired value.
$('.reg_field').each( function() {
group_text[form_count] = $(this).val();
form_count++;
});
I suspect the issue was my previous selector was unable to use $(this), which seems to work in more cases for appended elements. Another possibility that was brought up in the comments was the use of nth-child in the middle of a selection. I am not sure on these points, and would appreciate a better explanation. Hopefully this will help for someone who faces the same issue. Also, I appreciate the help on getting me to focus on the selection rather than the binding.

Related

Duplicating IDs Jquery

So, I have done some research, and it's pretty clear that id should be unique in the DOM. This is my issue, and I am curious what the best solution to it is:
I am using jQueryUI tabs as well as a custom menu and ajax to load specific pages into a content pane without re-rendering the browser. From some of these sub pages, a user can open a popup (done with a jQueryUI dialog) to edit customer information. Because these load a server side page, in each place that this form would be generated, it uses the same ids.
I have found that there are a number of ways to close a dialog without removing it from the DOM. This causes confusion later when it, or another form is opened elsewhere, and now there are conflicting ids present in the DOM. I am working on tracking down all the ways to close a dialog, and making sure to replace them with .dailog("destroy").remove() to make sure that they are erased from the DOM, but I want to be sure the solution here is fool proof in the event that someone one gets left on the page.
My two immediate thoughts:
1.) Generate a random string to append to each form element's id when the form is rendered, fully preserving uniqueness of the id.
2.) Use more specified selectors when getting the form data, i.e. scoping it to the popup that was created, the page that it was created from, and then the tab that it is under, and not worrying as much about id uniqueness.
The first feels ugly, and in theory you COULD randomly duplicate the string and still run into an issue. The later just feels bulky and ugly to me. Is there an option I am missing? What is best practice when it comes to dealing with IDs that can be duplicated in this way?
Thanks,
Eric
You may use classes if you need "similar" objects. Id's purpose is to identify object uniquely.
By the way, classes are widely used, for example, in Bootstrap.
UPDATE: I think your "second" approach is bad, as you eventually can change the layout, but, in this way, you should track every change, and remember WHERE to change your selectors (possibly, it will be multiple places).
Before inserting the new element into the list, you could check if there is already an element existing on the page with that id. If it does exist than delete it.
Like:
if($("#"+your_id).length!==0)
$("#"+your_id).remove();
//insert the new element
But if you need that element as well, i would suggest that you use classes to group elements used for same purposes.
Here is what you can do to distinguish between the different dialogs when you try to close them:
1) Change each dialog id into a class, so that your dialogs can share the same class. Using the same id is not recommended.
2) You can create a click listener for the button that closes the correct dialog by using the event callback parameter. See the working snippet below.
var closeButtons, i, closeButtonsLen;
closeButtons = document.getElementsByClassName('close');
for (i = 0, closeButtonsLen = closeButtons.length; i < closeButtonsLen; i += 1) {
closeButtons[i].addEventListener('click', function (e) {
e.target.parentNode.setAttribute('hidden', true); // if you want to hide the dialog
});
}
<div class="dialog"><button class="close">first x</button></div>
<div class="dialog"><button class="close">second x</button></div>
<div class="dialog"><button class="close">third x</button></div>
You can replace e.target.parentNode.setAttribute('hidden', true); with whatever you need to do. e.target.parentNode gets the dialog element.

Jquery remove function follow up

I submitted this question last week:
chrome not working with jquery remove
and was able to resolve it (stupidity on my part really), however my example was very simple. Currently I'm trying to use .remove to eliminate a complete div from a page before sending an array of inputs to an ajax function. However, I am not able to get .remove to work at all.
Here's my latest try:
http://jsfiddle.net/CJ2r9/2/
I get function not defined on the jsfiddle on multiple browsers. On my application I get absolutely no errors, but nothing works either.
I'm relatively new to javascript scopes, so if the problem is scope-wise then please let me know how I'm screwing up.
I have also tried using the .on jquery function, but it's a bit more confusing considering my div ids are dynamically loaded from the server (jstl, spring MVC, etc). If that's a solution please let me know how I can get on the right track.
Thank you!
The two problems in your jsFiddle are:
Scope: removeElem is not in global scope, since you left the default configuration option to execute the code on DOM ready. You can change it to "no wrap" to make the funciton global.
The elements you want to remove don't exist. The div elements have IDs like "removeXXXp" and in your event handlers you pass "removeXXXs".
Here is an other, simpler solution (in my opinion) for element removal. Given your markup:
<div class="scheduleSet" id="remove315p">
<!-- ... -->
Remove
</div>
You can use .on like so:
$('.schduleSet a.optionHide').on('click', function() {
// traverses up the DOM tree and finds the enclosing .schduleSet element
$(this).closest('.scheduleSet').remove();
});
You don't even need IDs at all.
I made a simple fiddle, the inline onclick doesn't see the function defined in javascript so I get a ReferenceError: myRemove is not defined.
By adding the listener in js, .remove() works fine.
Sorry I don't know what causes the difference in behavior though.
Test it out: http://jsfiddle.net/xTv5M/1/
// HTML5
<div id="removeme">foo bar</div>
<button onclick="myRemove('removeme')">Go</button><br>
<div id="removeMe2">foo bar</div>
<button id="go2">Go Again</button>
// js
function myRemove(name){
$('#'+name).remove()
};
$('#go2').click(function(){ myRemove('removeMe2') });
I see that you are already using jquery. Why dont you do it this way:
<div id="foo">This needs to be removed</div>
Remove
function removeElem(element){
$('#'+element).remove();
}
$(function(){
$("#remove").click(function(){
removeElem($(this).data('remove'));
});
})
Fiddle here: http://jsfiddle.net/vLgpk/
They way this works is, using data-remove (can be anything like data-xyz btw), binds the remove link with the div. You can then read this binding later when remove is clicked.
If you are new to jQuery, and wondering what data-remove is, its just custom attribute that you can add to you code which can be later retrieved using the data() call on the element. Many great frameworks like Bootstrap use this approach.
Advantage of using this approach in my opinion is you can have the remove links anywhere in your UI and they don't need to be related structurally to your divs by siting inside them.

Why is clone only cloning item once?

I'm new to jquery and I'm 100% sure I'm making a logical error but I can't see it. Basically as a user types a item in a field I want to clone the fields so they can continue adding more info. In the example I'm working on, I'm trying to create a list of siblings and their age.
Here's my code:
$(document).ready(function () {
$("input[name='age']").on('keydown', function() {
//is it the last input?
if (this == $("input[name='age']:last", this.form)[0]) {
//insert an empty clone of the current input
//$(this).after($(this).clone(true).val(''));
$('.family').clone().insertAfter(".family");
}
Here's the html:
<form>
<div class="family">
<input name="age" value=0> <input name="sibling" value="name?">
<hr />
</div>
</form>
If I use $(this).after($(this).clone(true).val('')); then it works but it only clones one field(the age one) so I tried to replace it with $('.family').clone().insertAfter(".family"); to clone the div class but it clones the fields only once. If I start typing my first siblings info then the second form will appear but if I start typing on the second form then nothing new appears after that.
Its just a guess but I think the if statement is not matching so the clone isn't being created(I'm new so this idea could be wrong). If this is the case then I'm confused because I'm cloning the same names of the input fields so input[name='age']:last should match the last age field..not sure.
Any idea what I'm doing wrong?
You're going to have to make your keydown event handler take note of future elements as well (i.e. the new <div> elements you're cloning and inserting).
Change
$("input[name='age']").on('keydown', function() {
to
$('form').on('keydown', 'input[name="age"]', function () {
i.e. (with some corrections / optimizations as well)
$('form').on('keydown', 'input[name="age"]:last-child', function() {
var _p = $(this).parent('.family');
// insert an empty clone of the current input's containing div
// ADDED : ... after the current input's containing div
_p.clone().insertAfter(_p);
}
Try this:
$("form").on('keydown',"input[name='age']:last", function() {
$('.family:last').clone().insertAfter(".family:last");
})
jsFiddle example
The issue is that you're trying to bind to elements that don't yet exist. To do that using .on(), you just need to bind to an element that exists in the dom:
Event handlers are bound only to the currently selected elements; they
must exist on the page at the time your code makes the call to .on().
To ensure the elements are present and can be selected, perform event
binding inside a document ready handler for elements that are in the
HTML markup on the page. If new HTML is being injected into the page,
select the elements and attach event handlers after the new HTML is
placed into the page. Or, use delegated events to attach an event
handler, as described next.
Then, you want to make sure you're only checking and cloning the last div and it's input. Note that when you're cloning the input fields, you will need to either change the names so you don't end up with a bunch of them that use the same name, or with a language like PHP you can append [] after the name and PHP will parse that into an array.

jQuery dynamic checkbox event handling

When appending HTML from a JSON reply, the event handlers appear to lose their event bindings. In using the .live() function the handler now appears to work.
$.each(result[0], function(i,wellList) {
$jsonResult = wellList["#name"];
$uid = wellList["#uid"];
$dynamicCheckBoxDiv += '<input type="checkbox" name="checkbox-1" value="'+ $uid
+ '" class="wellCheck" id="checkbox-'+i+'" />' +
'<label for="checkbox-'+i+'">' + $jsonResult + '</label>';
});
$dynamicCheckBoxDiv += '</fieldset></div>';
//Append results to div
$("#dynamicCheck").append($dynamicCheckBoxDiv).page();
$(".wellCheck").live('click', (function() {
This event now fires when the click function is run. However, after clicking the checkbox a few times, it randomly associates the checks with the wrong boxes and starts to fire the click event fire on a single click. Has anyone seen this before?
Also: How could I add a method to check all the boxes in a separate button? Since they are being added dynamically it seems to just bypass this function:
// When select No wells is clicked this method is run
$('#selectNone').click(function() {
$('#dynamicCheck .wellCheck').find(':checkbox').attr('checked', 'checked');
});
It enters the method, but doesnt seem to check any of the boxes. I have jQuery and jQuery mobile added to this page and both methods exist under document.ready.
You don't need to find(":checkbox") since the .wellCheck element is the checkbox. Just do this:
$("#selectNone").click(function(){
$("#dynamicCheck .wellCheck").prop("checked", true);
});
Demo.
Explanation of the first bit is that the written-into-HTML listeners only apply on page load. Any time you're adding raw HTML to the page, you have to set any listeners specifically. Similarly, just changing the "onclick" attribute does nothing to the listeners.
I suspect your problem with the second bit has something to do with the fact that, at least by my reading, '$(".wellCheck").live(...)' is going to affect every box you've created thus far each time. You might be better served by something like '$dynamicCheckBoxDiv.live(...)'
I'm not entirely clear on the precise syntax - I worked more with cloned HTML rather than manually constructed, so you may need an intervening step to render it into a DOM object or something (if it's not one already) - but I suspect something like this will help.
Also, you might wish to use '.click(...)', rather than '.live("click", ...)'.
You should use delegate not live:
$("#dynamicCheck").delegate('.wellcheck','click', function(){
//stuff on click
});
This would be better bound at that scope than at the body which is what live does.
EDIT: See this for some examples of checkbox management: http://jsfiddle.net/h682v/3/
That uses older attr() and should use prop() instead but the principle remains.

How to work with dynamically created fields?

I have web layout, which can contains several links on it. Those links are dynamically created, using AJAX functions. And it works ok.
But, I don't know how can I work with those "dynamically created links" (ie. how to call some JS or jQuery function if I click on them). I guess that browser can not recognize them, since there are created after page is loaded.
Is there some function, that can "re-render" my page and elements on it?
Tnx in adv on your help!
You can use the 2 following methods jQuery provides:
The first one, is the .live() method, and the other is the .delegate() method.
The usage of the first one is very simple:
$(document).ready(function() {
$("#dynamicElement").live("click", function() {
//do something
});
}
As you can see, the first argument is the event you want to bind, and the second is a function which handles the event. The way this works is not exactly like a "re-rendering". The common way to do this ( $("#dynamicElement").click(...) or $("#dynamicElement").bind("click", ...) ) works by attaching the event handler of a determinate event to the DOM Element when the DOM has properly loaded ($(document).ready(...) ). Now, obviously, this won't work with dynamically generated elements, because they're not present when the DOM first loads.
The way .live() works is, instead of attaching the vent handler to the DOM Element itself, it attaches it with the document element, taking advantage of the bubbling-up property of JS & DOM (When you click the dynamically generated element and no event handler is attached, it keeps looking to the top until it finds one).
Sounds pretty neat, right? But there's a little technical issue with this method, as I said, it attaches the event handler to the top of the DOM, so when you click the element, your browser has to transverse all over the DOM tree, until it finds the proper event handler. Process which is very inefficient, by the way. And here's where appears the .delegate() method.
Let's assume the following HTML estructure:
<html>
<head>
...
</head>
<body>
<div id="links-container">
<!-- Here's where the dynamically generated content will be -->
</div>
</body>
</html>
So, with the .delegate() method, instead of binding the event handler to the top of the DOM, you just could attach it to a parent DOM Element. A DOM Element you're sure it's going to be somewhere up of the dynamically generated content in the DOM Tree. The closer to them, the better this will work. So, this should do the magic:
$(document).ready(function() {
$("#links-container").delegate("#dynamicElement", "click", function() {
//do something
});
}
This was kind of a long answer, but I like to explain the theory behind it haha.
EDIT: You should correct your markup, it's invalid because: 1) The anchors does not allow the use of a value attribute, and 2) You can't have 2 or more tags with the same ID. Try this:
<a class="removeLineItem" id="delete-1">Delete</a>
<a class="removeLineItem" id="delete-2">Delete</a>
<a class="removeLineItem" id="delete-3">Delete</a>
And to determine which one of the anchors was clicked
$(document).ready(function() {
$("#links-container").delegate(".removeLineItem", "click", function() {
var anchorClicked = $(this).attr("id"),
valueClicked = anchorClicked.split("-")[1];
});
}
With that code, you will have stored in the anchorClicked variable the id of the link clicked, and in the valueClicked the number associated to the anchor.
In your page initialization code, you can set up handlers like this:
$(function() {
$('#myForm input.needsHandler').live('click', function(ev) {
// .. handle the click event
});
});
You just need to be able to identify the input elements by class or something.
How are these links dynamically created? You can use use the correct selector, given that they are using the same class name or resides in the same tag, etc.
consider the html form
<form>
<input type="text" id="id" name="id"/>
<input type="button" id="check" name="check value="check"/>
</form>
jquery script
$('#check).click(function() {
if($('#id).val() == '') {
alert('load the data!!!!);
}
});
here on clicking the button the script check the value of the textbox id to be null. if its null it will return an alert message....
i thin this is the solution you are looking for.....
have a nice day..
Noramlly , the browser process response HTML and add it to DOM tree , but sometimes , current defined events just not work , simply reinitialize the event when u call the ajax request ..
All you need to do to work with dynamically created elements is create identifiers you can locate them with. Try the following code in console of Firebug or the developer tools for Chrome or IE.
$(".everyonelovesstackoverflow").html('<a id="l1" href="http://www.google.com">google</a> <a id="l2" href="http://www.yahoo.com">yahoo</a>');
$("#l1").click(function(){alert("google");});
$("#l2").click(function(){alert("yahoo");});
You should now have two links where the ad normally is that were dynamically created, and than had an onclick handler added to bring up an alert (I didn't block default behaviour, so it will cause you to leave the page.)
jQuery's .live will allow you to automatically add handlers to newly created element.
If your links are coming in via AJAX, you can set the onclick attributes on the server. Just output the links into the AJAX like this:
Holy crap I'm a link
The return false makes sure the link doesn't reload the page.
Hope this helps!

Categories