Nesting scripts? - javascript

I have an empty div, like this:
<div id="my-content"></div>
Then i have some jQuery, something like this:
/**IGNORE THIS**/
function makeButton(){
$('#my-content').html('<input type="button" value="Say hey" id="my-button" />');
}
So far, so good.
Then i have this js:
$(document).ready(function(){
makeButton();
});
Works perfect, but, when i after this makes a trigger for this button, so it looks like the following, it does not respond to the button id...
$(document).ready(function(){
makeButton();
$('#my-button').click(function(){
alert('Hello!');
});
});
I can of course add <script>$(document).ready... blah... alert('Hello');</script> into the .html() in the makeButton function, but i guess that's not the real way to do it.
How will i tell the JS to start listen for clicks AFTER makeButton() is ready and has added the button?
EDIT:
Ok, that works. Sorry. The actual case is not really like the above, but similar.
the makeButton() is actually another function that gets data by ajax, so makeButton is more like this:
makeButton(){
$.ajax({
type: 'POST',
url: 'ajax_images.php',
data: {pageNr: pageNr},
success:function(response) {
//Loops the json and does something like this:
var HTML = '<div id="thumbnail">;
HTML += 'Response Stuff'
HTML += '</div>';
$('#my-content').html(HTML);
}
});
}
Sorry for beeing confusing.

The problem is that you are trying to bind the event handler before the element exists. The Ajax call is asynchronous!
You can return the promise object from the $.ajax call:
function makeButton(){
return $.ajax({
// ...
});
}
and then bind the event handler when the Ajax call succeeded by adding a callback:
makeButton().done(function() {
$('#my-button').click(function(){
alert('Hello!');
});
});
Alternatively you can use event delegation, as thecodeparadox shows in his answer. To learn a bit more about how Ajax works, have a look at this answer.

Just make a simple change:
$(document).ready(function(){
makeButton();
$('#my-content').on('click', '#my-button', function(){
alert('Hello!');
});
});
You need delegate event for #my-button as its coming to DOM tree after page load. To know more about delegate event binding in jQuery see here.

Related

Ajax sends request more than once

I have a huge problem with working with AJAX:
After the AJAX request on my page is send the next request are send multiple times, and buttons think that they are pressed multiple times.
Now I searched around here and the internet, but I can't solve it. So far, following corrections are made in the code:
All code is in an own function called AjaxInit()
AjaxInit() is called upon $(window).load and on $(document).ajaxStop
All Element have their binder to body (e.g. $("body").on("click","#btn-main", function)
Now I have tried unbinding all events using $("body").find("*").off(), but that did not help either.
I know that I do something wrong, I just don't know what.
How can I properly rebind everythink after the Ajax call is done? How can I make shure that object bindings (e.g. $("#news").sortable({})) will work properly after the first ajax call? I would love to use AJAX for all the callbacks on my page, but currently the best solution seems to be just reloading the entire page after every ajax call, which would be rather bad.
Any help is appreciated.
EDIT: Code added
$(window).load(function() {
AjaxInit();
});
$(document).ajaxStop(function() {
AjaxInit();
});
function AjaxInit() {
$("body").on("click", "#btn-admin-main", function(e) {
console.log("Admin clicked");
e.handled = true;
e.preventDefault();
LoadDynamicContent("/Edit/");
});
}
function LoadDynamicContent(path) {
//Nach oben Scrollen
$('html,body').scrollTop(0);
$.ajax({
type: 'GET',
url: path,
success: function(response) {
var html_response = $(response).find('#dynamic_content').html();
$("#dynamic_content").html(html_response);
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<a class="sidebutton-full" id="btn-main">Edit</a>
<div id="dynamic_content"></div>
You can unbind the click event from button
$(document).unbind('click').on("click", "#btn-main", function () {
//do stuff here
});
OR
$(document).off("click", "#btn-news").on("click", "#btn-news", function () {
});
If your form submission hitting twice then you need to change your code little bit
$("#form_news_sort").submit(function(e){
e.preventDefault()
// do stuffer here
.
.
.
.
return false;
})
if you are still facing error , please comment below
The problem is that when your ajaxStop handler calls AjaxInit(), it adds another click handler to the body.
In your example code, it looks like you don't need ajaxStop at all. All it will do is add another click handler, which is the problem. Or if your real code does some more complex initialization that needs to run whenever all Ajax requests are complete, you should factor out the click handler assignment from whatever else needs to happen.

ajax at once and at two

$(function(){
$('a.ajaxLink').click(function(e){
var l = $(this).attr("href"),
getdata;
if(l != null){
e.preventDefault();
$.ajax({
type:'GET',
url:l + '#book',
success:function(result){
getdata = $(result).find('#book');
//$('#content').html(getdata);
$('#content').fadeOut(function(){
$('#book').remove();
$('#content').append(getdata);
});
$('#content').fadeIn(function(){
pos();
});
}
});
}
});
});
Hello, I have this code as above :) but there is a problem with the other files Loads multiple addresses with ajaxLink and then ajax does not work. It is something like this: the first click loads the partition with in the background the second click on a loaded by ajax page no longer works.
Looks like you replace the whole page or a part which contains your link, so the event bindning will no longer work. To make it work you should use jquery on function.
$(document).on('click', 'a.ajaxLink', function(e){.... your handler goes here})
Use the .on() event handler rather than .click() because the .on() can handle new DOM elements but .click() dose not

JQuery event handler when select element is loaded

Is there an event handler to use in JQuery when a DOM select element has finished loading?
This is what I want to achieve. It is working with other events except 'load'.
This piece of code is loaded in the head.
$(document).on('load', 'select', function(){
var currentSelectVal = $(this).val();
alert(currentSelectVal);
} );
The question was badly formed earlier. I need to attach the event handler to all select elements, both present when the document is loaded and dynamically created later.
They are loaded from a JQuery Post to a php-page. Similar to this:
$.post("./user_functions.php",
{reason: "get_users", userID: uID})
.done(function(data) { $("#userSelector").html(data);
});
I think we're all confused. But a quick break down of your options.
After an update made to the Question, it looks like the answer you might seek is my last example. Please consider all other information as well though, as it might help you determine a better process for your "End Goal".
First, You have the DOM Load event as pointed out in another answer. This will trigger when the page is finished loading and should always be your first call in HEAD JavaScript. to learn more, please see this API Documentation.
Example
$(document).ready(function () {
alert($('select').val());
})
/* |OR| */
$(function() {
alert($('select').val());
})
Then you have Events you can attach to the Select Element, such as "change", "keyup", "keydown", etc... The usual event bindings are on "change" and "keyup" as these 2 are the most common end events taking action in which the user expects "change". To learn more please read about jQuery's .delegate() (out-dated ver 1.6 and below only), .on(), .change(), and .keyup().
Example
$(document).on('change keyup', 'select', function(e) {
var currentSelectVal = $(this).val();
alert(currentSelectVal);
})
Now delegating the change event to the document is not "necessary", however, it can really save headache down the road. Delegating allow future Elements (stuff not loaded on DOM Load event), that meet the Selector qualifications (exp. 'select', '#elementID', or '.element-class') to automatically have these event methods assigned to them.
However, if you know this is not going to be an issue, then you can use event names as jQuery Element Object Methods with a little shorter code.
Example
$('select').change(function(e) {
var currentSelectVal = $(this).val();
alert(currentSelectVal);
})
On a final note, there is also the "success" and "complete" events that take place during some Ajax call. All jQuery Ajax methods have these 2 events in one way or another. These events allow you to perform action after the Ajax call is complete.
For example, if you wanted to get the value of a select box AFTER and Ajax call was made.
Example
$.ajax({
url: 'http://www.mysite.com/ajax.php',
succuess: function(data) {
alert($("select#MyID").val());
}
})
/* |OR| */
$.post("example.php", function() { alert("success"); })
.done(function() { alert($("select#MyID").val()); })
/* |OR| */
$("#element").load("example.php", function(response, status, xhr) {
alert($("select#MyID").val());
});
More reading:
.ajax()
.get()
.load()
.post()
Something else to keep in mind, all jQuery Ajax methods (like .get, .post) are just shorthand versions of $.ajax({ /* options|callbacks */ })!
Why dont you just use:
$(document).ready(function () {
//Loaded...
});
Or am I missing something?
For your dynamic selects you can put the alert in the callback.
In your .post() callback function, try this:
.done(function(data) {
data = $(data);
alert(data.find("select").val());
});
Ok, correct me if I understand this wrong. So you want to do something with the selects when the document is loaded and also after you get some fresh data via an ajax call. Here is how you could accomplish this.
First do it when the document loads, so,
<script>
//This is the function that does what you want to do with the select lists
function alterSelects(){
//Your code here
}
$(function(){
$("select").each(function(){
alterSelects();
});
});
</script>
Now everytime you have an ajax request the ajaxSend and ajaxComplete functions are called. So, add this after the above:
$(document).ajaxSend(function () {
}).ajaxComplete(function () {
alterSelects();
});
The above code will fire as soon as the request is complete. But I think you probably want to do it after you do something with the results you get back from the ajax call. You'll have to do it in your $.post like this:
$.post("yourLink", "parameters to send", function(result){
// Do your stuff here
alterSelects();
});
Do you want all Selects to be checked when the User-Select is loaded, or just the User-Select?...
$.post("./user_functions.php", {reason: "get_users", userID: uID}).done(function(data) {
$("#userSelector").html(data);
//Then this:
var currentSelectVal = $("#userSelector").val();
alert(currentSelectVal);
});
If your select elements are dynamically loaded, why not add the event handler after you process the response?
e.g. for ajax
$.ajax({
...
success: function(response) {
//do stuff
//add the select elements from response to the DOM
//addMyEventHandlerForNewSelect();
//or
//select the new select elements from response
//add event handling on selected new elements
},
...
});
My solution is a little similar to the posters above but to use the observer (pubsub) pattern. You can google for various pub sub libraries out there or you could use jQuery's custom events. The idea is to subscribe to a topic / custom event and run the function that attach the event. Of course, it will be best to filter out those elements that have been initialize before. I havent test the following codes but hopefully you get the idea.
function attachEventsToSelect(html) {
if (!html) { // html is undefined, we loop through the entire DOM we have currently
$('select').doSomething();
} else {
$(html).find('select').doSomething(); // Only apply to the newly added HTML DOM
}
}
$(window).on('HTML.Inserted', attachEventsToSelect);
// On your ajax call
$.ajax({
success: function(htmlResponse) {
$(window).trigger('HTML.Inserted', htmlResponse);
}
});
// On your DOM ready event
$(function() {
$(window).trigger('HTML.Inserted'); // For the current set of HTML
});

How to elegantly disable/enable all jQuery UI buttons?

I currently have several action buttons in different pages, and each button performs some AJAX call when clicked. In another word, I have code like this all over the places:-
$("#searchButton")
.button()
.click(function() {
...
$.get(url, { data: ...}, function(data) { ... });
...
});
After doing some testing, it seems like some AJAX calls take at least more than a few seconds to process before the callback function is being called.
My plan is to disable the button when the AJAX call is made and enable it back when the AJAX call is completed. This is to prevent user from clicking the button too many times when the request is being processed. One solution I found is to utilize the unbind() and bind() functions. After modifying my code, it looks like this now:-
var searchButtonClickHandler = function() {
...
$.get(url, { data: ...}, function(data) { ... });
...
};
$("#searchButton")
.button()
.ajaxStart(function() {
$(this).button("disable").unbind("click");
})
.ajaxStop(function() {
$(this).button("enable").bind("click", searchButtonClickHandler);
})
.click(searchButtonClickHandler);
This code works fine. Basically, it removes the click handler when the AJAX call is made and addes the click handler back when the AJAX call is completed.
My question is... is it possible to generalize the button disabling/enabling so that I don't have to implement ajaxStart() and ajaxStop on all UI buttons?
Ideally, I would like to use my earlier code snippet to register only the click event handler on the button, and then enable/disable all buttons using the .ui-button selector, something like this...
$(".ui-button")
.ajaxStart(function() {
$(this).button("disable").unbind("click");
})
.ajaxStop(function() {
// not sure how to bind the handler here
$(this).button("enable").bind("click", ?? );
});
... but, this doesn't work and I run into trouble in binding the click handler here.
The more I think about it, it almost seems like I need to create a button builder function to do this, for example:-
var createButton = function(selectorName, clickHandler) {
$(selectorName)
.button()
.ajaxStart(function() {
$(this).button("disable").unbind("click");
})
.ajaxStop(function() {
$(this).button("enable").bind("click", clickHandler);
})
.click(clickHandler);
};
// create button like this
createButton("#searchButton", function() {
...
$.get(url, { data: ...}, function(data) { ... });
...
});
... but this approach will only disable/enable the selected button, and I want to apply that to all UI buttons.
Do anyone has a better approach in disabling/enabling all the buttons in the page?
Thanks.
Different approach, according to this answer you should be able to get a reference to your previous event handler via .data("events");
Putting that together with your sample it should look like this:
$(".ui-button")
.ajaxStart(function() {
var events = $(this).data("events");
$(this).data("oldEvent", events.click[0]);
$(this).button("disable").unbind("click", events.click[0]);
})
.ajaxStop(function() {
var oldClick = $(this).data("oldEvent");
$(this).button("enable").bind("click", oldClick.handler);
});
Not sure if this will work completely yet, still messing around on jsfiddle.
Update
This should work, example on jsfiddle.
you can use $('input[type=button]').attr('disabled','disable'); to disable all buttons instead of binding and unbinding click event to the buttons... also you can use deferred jquery object, here is an example
Maybe you could attach your handler to the parent element of your buttons with delegate? That way there's only one handler function to bind/unbind.
Yahoo hosts a getElementByClass function, and you could assign a class such as "disableMe" to all your UI buttons. Then use getElementByClass('disableMe') to return an array of all the elements you want to disable.
The link: http://developer.yahoo.com/yui/dom/
You can use
$("button").each(function(){
//your code here
});

Using jQuery replaceWith to replace content of DIV only working first time

I'm using the following jQuery to pull new data and replace the contents of the DIV listdata
$(function(){
$('.refresh').click(function(event) {
event.preventDefault();
$.ajax({
url: "_js/data.php",
success: function(results){
$('#listdata').replaceWith(results);
}
});
});
});
The script is triggered by numerous links on the page, such as:
Update 1
Update 2
For some reason the script only works on the first click of a link. Subsequent clicks do not refresh the data.
I've seen various fixes but nothing that I can get working. Any suggestions?
It looks to me like your problem is with using replaceWith.
You're removing the element which matches $('#listdata') on the first call of replaceWith, so subsequent refreshes can't find where the data is supposed to be placed in the document.
You could try something like
$('#listdata').empty();
$('#listdata').append(results);
or chained like this
$('#listdata').empty().append(results);
If you're using replaceWith(), you're replacing #listdata with a brand new element altogether.
If data isn't something like <div id="listdata"></div> then #listdata is disappearing after the replaceWith(). I'm thinking you should probably use html() instead.
You'll need to change the href's on your links to .... This prevents the browser from refreshing when you click the link.
If you're doing things this way, you'll also want to stick a "return false" at the end of the click handler to prevent bubbling.
Try:
$('a.refresh').live('click', function(e) {
e.preventDefault();
$.ajax({
url: '_js/data.php',
success: function(data) {
$('#listdata').empty().html(data);
}
});
});
If the .refresh anchors are inside the #listdata element, then delegation is a more optimized solution:
var list = $('#listdata');
list.delegate('a.refresh', 'click', function(e) {
e.preventDefault();
$.ajax({
url: '_js/data.php',
success: function(data) {
list.empty().html(data);
}
});
});

Categories

Resources