I'm trying to fire the click event on an element that is loaded via ajax.
But somehow i cannot select it right to fire the event.
It is basically an image with left, right arrows. if you click on one of the arrows a series of images gets loaded and replaced the images like a gallery. That's works already, i just need to fire the first slide so the user doesn't get that the gallery has been loaded via ajax but was there all the time.
The replacement works fine, but i cannot fire the event on the .slidenav-next element.
There is JS behaviour behind .slidenav-next that needs to be triggered by an click.
Base HTML structure
<div><div class="slidecont"></div></div>
JS to fill it with new HTML structure
$('body').on('click', '.slide', function(e) {
$.ajax({
context: this,
type: "POST",
url: 'index.php',
data: {'id':5}
}).done(function(data) {
$(this).closest('.slidecont').replaceWith(data);
console.log($(data).find('.slidenav-next'));
setTimeout(function () {
$(data).find('.slidenav-next').click();
}, 200);
});
});
HTML structure that gets loaded via ajax
<div></div>
In the end
<div><div></div></div>
If i load this structure:
<div id="xx"></div>
I can trigger it via:
$('#xx > .slidenav-next').click();
or via
$('body').find('.slidenav-next').click();
But that's not so clean. I would like to trigger it from within the loaded data.
var $data = $(data);
$(this).closest('.slidecont').replaceWith($data);
$data.find('.slidenav-next').click();
this way will create a jquery object from the data... that object then gets inserted into the DOM with replaceWith and can be referenced later.
just replacing with data directly doesnt put the data var itself as a element that exists in the DOM and can be referenced from data... data is still just a string...
could also have done something like this at the beginning of the done callback..
var div = document.createElement('div');
div.innerHTML = data; //this creates a child element based on the string in data
var dataEle = div.firstChild; //then we take that child
now dataEle references an element created based on the data string that can be inserted (like with replaceWith(dataEle)) and referenced later (like with $(dataEle).find(...)
More explanation of what was wrong:
you don't need to insert a jquery object as can be seen in the second example. jquery just takes over the job of creating a dom element and maintains access to it so you can reference it later.
the problem you were having is that data was always just a string, you used that string to create a dom element with replaceWith... but data itself was still just a string.
then again when you did $(data).find('.slidenav-next').click(); it was wrapping data in a jquery which created it's own element using the string in data (although data is still just a string) and did indeed fire off the event... however the event got fired off on the the newly created jquery wrapped element that was not ever inserted into the body of the DOM rather than the element you created with replaceWith
you were basically creating two elements from the data string, putting the first one where you wanted it but then firing off the event on the second one which was never inserted anywhere.
Related
To preface, say that we have a custom element that looks just like the one from this Autonomous custom element section from here: example code
and after the page loads you wish to create a new custom element by doing something like this:
var exampleElement = document.createElement("popup-info"); //creates element
var exampleElementImg = document.createAttribute("img"); //does not get executed until the parser has put other dom in from the custom element
exampleElementImg.value = "img/alt.png";
exampleElement.setAttributeNode(exampleElementImg);
var exampleElementText = document.createAttribute("text");
exampleElementText.value = "Hello World!";
exampleElement.setAttributeNode(exampleElementText);
//append exampleElement somewhere to the document
normally this would be fine but immediately when createElement() gets executed it starts appending the extra DOM immediately, but it does not wait for createAttribute()
I was wondering if there would be a way to get this to create the attributes before the element get parsed without using something like timeout in the constructor.
Since that is a class you can create a separate function within that class like ‘create’ and within that function is where you have all of the appending functions that append the objects to the shadow dom and wrapper.
Then call it like below after you have added the attributes and so on.
‘exampleElement.create();’
The API docs for appendTo list the method being able to select an HTML string for a target.
However, there seems to be no use to this since the set still includes the original elements, and the HTML string seems not to have been added anywhere in the DOM nor do I see a circumstance where it could be available.
var b = button.appendTo('<div>').appendTo('body');
b is a button, and yet it is not wrapped in a div or anything.
You can see this at http://jsfiddle.net/0dgLe5sj/
Where would it be useful to append to a HTML string (which doesn't yet exist on the page)?
appendTo() returns the item being appended.
So your code is:
var btn = button.appendTo('<div>');
btn.appendTo('body');
As you can see, you move it inside a div, then immediately move it inside the body. So you when you look at it at the end, it's inside the body.
Perhaps you meant:
var b = button.appendTo($('<div>').appendTo('body'));
which will append a div to the body and then append the btn to that div.
Updated fiddle: http://jsfiddle.net/0dgLe5sj/8/
or, if you wanted to add to the div first:
var b = button.appendTo("<div>");
b.parent().appendTo("body")
but if you combine it into a single line, you can't get the button back into the variable using .appendTo as you're adding the div to the body so you're going to get the div or the body back.
To address the 'where would this be useful part':
Being able to create detached DOM elements is extremely useful for parsing HTML strings and can also be used to 'batch' up some changes without forcing page redraws between.
Moving one button to a detached div and the back to the body doesn't have a lot of point, but it proves the principles.
I want to know what's the best practise for updating DOM after an Ajax call.
For example, imagine we have a list of users and we can add a user with a form which make an Ajax call to insert the user. After the form is submitted and the user added in database, the DOM is edited to add HTML without refreshing the page (with the Ajax success event).
I see two possibility to make this :
Make an Ajax call who add the user in db and return all the DOM structure with html tag, etc.
Make an Ajax who add the user in db and return all the data of an user and create the DOM element in Javascript
What'is the best way to do it (or another way) ?
You can add elements to the DOM with document.createElement(). Then use the innerHTML property to add content to the element. Finally append the element to another with .appendChild().
There is no better way between the two options. You can either prepare your HTML structure in the backend and import the written HTML and directly append it with JavaScript or create the elements frontend in JavaScript.
Here are the main advantages to using the latter:
it's easier to debug JavaScript than PHP (PHP files targetted by AJAX calls are quite hard to debug and to maintain).
returning an object with AJAX instead of an HTML string is easier to use and more maintainable. You can have an API to handle the data. PHP only returns a JSON object.
if JavaScript handles the creation of elements, you can save those in variables. Sometimes, I find it useful to save an HTMLElement in a JavaScript variable so I can later access it to change its properties without having to go through selectors (querySelector() and others).
I would go with the second option
Make an Ajax who add the user in db and return all the data of an user and create the DOM element in Javascript
Breaking it down like so to improve on readability and maintenance
Add action to AJAX that is linked to a function on the backend, (i.e PHP, Python) that does the DB update and more.
Create the Element structures in Javascript (You can maintenance uniformity with other structures on your page). And wrap it in a function.
document.body.onload = addElement;
function addElement ($newuser) {
// create a new div element that would contain user record
var newDiv = document.createElement("div");
// and give it some content
var newContent = document.createTextNode($newuser);
// add the text node to the newly created div
newDiv.appendChild(newContent);
// add the newly created element and its content into the DOM
var currentDiv = document.getElementById("user-container");
document.body.insertBefore(newDiv, currentDiv);
}
I am attempting to fire off an AJAX call based on the onclick event for a google map integration. The info_window_content function seen here: http://jsfiddle.net/6xw2y/ is the call to create the divs that reside within the map itself.
The "v" variable does in fact contain a store_id. So in the opening line of that function, it has the following:
var info_window_string = "<div class='maps_popup' id="+v.id+">";
Now I have an onclick event that I have duplicated and modified. The first onclick event works just fine and refreshes the panel as it should. The second onclick event doesn't work and the code for that is below:
$("#div").click(function(){
var store_id = $(this).find("div").attr("id");
var pathname = "ajax=1&store_id="+store_id+"&action=get_nearby_stores&distance="+distance+"&lat="+lat+"&lng="+lng+"&products="+$('#edit-products').val();
$("#pocp_content").load("file1.php?" + pathname);
});
That doesn't seem to work. I've also tried changing the div tag to be like this:
$("div").click(function(){
Which still doesn't work. As an added side hint. At one point I was able to get it to refresh but it was passing map-container as the store_id, instead of the id itself.
What am I missing here?
I agree with Joke_Sense10,
but I think you're probably not binding the event to the right DOM element.
Try to open up the developer console in your browser (while being on the side you develop this code for), and enter $("#div") to see if the element it returns is the one you expect. You can also use console.log($("#div")) in the code for that.
answer in comments
For a larger number of elements, always use .on() method as the latter will bind an single event listener on one of the topmost nodes in the DOM tree.
$(document).on("click","#"+v.id, function(){
I'm trying to detach a DOM element to append it to another DOM element. But jQuery refuses to do anything, silently.
Thing is, I can't use a string selector, because I don't know how to select this element. I've stored it in a variable when I first appended some html code to the initial parent (through "appendTo".
this.element = $(my_html_string).appendTo(some_dom_parent);
And that works fine. The code that is not working as expected, is following:
this.transferTo = function(dom_parent)
{
$(this.element).detach()
$(this.element).appendTo(dom_parent);
}
What happens is:
The element is NOT removed from wherever it is.
The element IS appended to the new parent.
Previously bind click events are triggered on both elements.
That click event appends a popup dialog to the element. It's being appended to the element in the new parent, always, regardless which one I click.
I tried some hardcoded detach like:
$('#very_specific_id').detach()
... and it works. But thing is, I don't have IDs placed around, and sounds like a very bad way to do this.
So the problem seems to rely on the fact I'm saving a jQuery DOM Element and trying to use .detach from it, instead of using a $(".query") like everyone else.
Ideas? Workarounds? Thanks!
Try changing this:
this.transferTo = function(dom_parent)
{
$(this.element).detach()
$(this.element).appendTo(dom_parent);
}
to this:
this.transferTo = function(dom_parent)
{
var $thisElement = $(this.element);
$thisElement.detach()
$thisElement.appendTo(dom_parent);
}