JQuery hover state for appended elements - javascript

I am writing a page that once loaded will go off and make an ajax call, process the json respose data, and then append these elements into the dom as shown in a simplified way below:
$.ajax({
type: 'POST',
url: "http://mysite.dev:32769/getallnews",
success: function(data){
$container.append(item)
.isotope( 'appended', item );
}
});
It should also be noted I am using Metafizzy's Isotope library. http://isotope.metafizzy.co/
To demonstrate my issue I have a <div class="article-block"></div> both in the DOM at load time and one more appended once the ajax call finishes.
this jquery will only capture the first and not the second though!
$(".article-block").hover(function(){
//hover on
$(".article-block div").fadeIn();
},function(){
//hover off
$(".article-block div").fadeOut();
});
I've spent some time debugging this and found that when I type $('.article-block'); into the console. I get both correctly. However when I hover over my first one the fade works, and when I hover over the second, it doesn't.
Any ideas?

Order matters
You are registering your event handler for the initial div when the page loads which is good. Its important to note that if you add dom elements later you will need to apply handlers to the new items.
Try saving a reference to your handlers and applying it later.
function hoverOn() {
$(".article-block div").fadeIn();
}
function hoverOff() {
$(".article-block div").fadeOut();
}
// on page load
$('.article-block').hover(hoverOn, hoverOff);
// later in the ajax call
$.ajax({
type: 'POST',
url: "http://mysite.dev:32769/getallnews",
success: function (data) {
$(item).hover(hoverOn, hoverOff); // register your hover event to the
// new element
$container.append(item).isotope( 'appended', item );
}
});

Related

Function initiated in ajax call only works one time

I am using a plugin called mixitup that makes sure I have a masonry layout with some animations.
The masonry comes from another page which gets loaded in through ajax. I have a search bar which searches for photos and returns them from the masonry page. The issue is this works the first time but not the second time and so on. Why is that?
My code for the search input:
$('.photosearchinput').keyup(function(e) {
clearTimeout($.data(this, 'timer'));
if (e.keyCode == 13){
searchphotos(true);
}else{
$(this).data('timer', setTimeout(searchphotos, 500));
}
});
My function that makes the ajax call and which has my masonry mixitup function in the complete:
function searchphotos(force) {
var photoform = $(".photosearchform").serialize();
$.ajax({
type:'post',
url:"includes/photoresults.php",
data:({photoform: photoform}),
success:function(data){
$( "#searchphotos" ).show().empty().append( data );
},
complete:function(){
// I tried calling #masongallery from the body (body always stays the same and does not get added again)
$('body').find('#masonrygallery').mixItUp({
selectors: {
target: '.tile',
filter: '.filter',
sort: '.sort-btn'
},
animation: {
animateResizeContainer: false,
effects: 'fade scale'
}
});
}
});
}
I thought maybe the DOM gets reloaded and jquery cannot find the element #masonrygallery anymore so I tried calling it like this: $('body').find('#masonrygallery').mixItUp({ the body never gets reloaded so maybe this would fix it, but no. I get the same result. It works the first time, but not any time after that.
I have made a video to show what I mean: https://streamable.com/njy6x7
I get no errors in my console. And when I look in the network tab to see what ajax is retrieving, I see the correct images, they are just not visible as masonry layout (in fact they are not visible on the page at all but this is because of the plugin).

the tooltip in bootstrap doesn't work after ajax

I have a file named index.php, which in I include another file named file1.php (in index.php I include all necessary files for jQuery, js etc.).
In file1.php I have a table with buttons which each opens a modal. the information in the modal is from an ajax call for file2.php. in file2.php I create a table. In the table I have the cell :
<button class='btn btn-default tooltip-default' data-toggle='tooltip' data-trigger='hover' data-placement='top' data-content='content' data-original-title='Twitter Bootstrap Popover'>AAA</button>
and, well, the tooltip doesn't work.
but, when I copy this and get it to file1.php, bellow the table, the tooltip does work.
Can anyone help me fix the tooltip ?
Thx.
Use selector on exist element like body
$('body').tooltip({selector: '[data-toggle="tooltip"]'});
I think you need to initialize the tooltip on the newly arrived data, e.g.
$('[data-toggle="tooltip"]').tooltip();
Place this code to your AJAX success handler, after the DOM manipulation.
You will have to put the tooltip initialization in Ajax callback function:
$.ajax({
method: "POST",
url: "some.php"
}).done(function( msg ) {
$('[data-toggle="tooltip"]').tooltip();
});
-OR-
instead of putting the initialization code in every Ajax callback function
you can implement it globally using the ajaxComplete event:
/* initializate the tooltips after ajax requests, if not already done */
$( document ).ajaxComplete(function( event, request, settings ) {
$('[data-toggle="tooltip"]').not( '[data-original-title]' ).tooltip();
});
This code will initialize the tooltip for every node which has the data-toggle="tooltip" attribute defined but do not have the attribute "data-original-title" (i.e tooltip not initialized).
I've tried everything and nothing worked for me.
So I took a closer look at tooltip when click* and found out that each time the shown.bs.tooltip is fired a aria-describedby property appears and its value changes every time.
So, my approach (and it works) is to change the content of this dynamic element.
I got this code:
$('body').on('shown.bs.tooltip', function(e) {
var $element = $(e.target);
var url = $element.data('url');
if (undefined === url || url.length === 0) {
return true;
}
var $describedByContent = $('#' + $element.attr('aria-describedby')).find('.tooltip-inner');
if ($element.attr('title').length > 1) {
$describedByContent.html($element.attr('title'));
return true;
}
$.ajax({
url: url,
method: 'GET',
beforeSend: function () {
$element.attr('title', 'Cargando... espere por favor.');
$describedByContent.html($element.attr('title'));
}
}).done(function (data) {
$element.attr('title', JSON.stringify(data));
$describedByContent.html($element.attr('title'));
});
return true;
});
In my case my tooltip has a data-url attribute to take the data for the title.
The original title is '-', and I don't want an ajax call every time I click* the element, just the first time.
To me it's not useful to make an ajax every time because I don't expect the data to change that fast.
The dynamic created element has an element with the class .tooltip-inner, so we just need to replace its content.
Hope this might help.
*click: I chose the click event because the default hover sometimes make the system turn crazy and the show.bs.tooltip was fired forever, switching its between the default and new value.
You can do this in one of these two ways:
you can write an ajaxComplete function so that every time after an ajax call completed it reinitialize the tooltip over and over again. This is useful when in most of your pages you have datatables and want to initialize the tooltip after every ajax datatable call:
$(document).ajaxComplete(function() {
$("[data-toggle=tooltip]").tooltip();
});
Or you can call tooltip function after ajax success callback:
function tool_tip() {
$('[data-toggle="tooltip"]').tooltip()
}
tool_tip(); // Call in document ready for elements already present
$.ajax({
success : function(data) {
tool_tip(); // Call function again for AJAX loaded content
}
})
I set up my tool tip by placement like so:
function setUpToolTipHelpers() {
$(".tip-top").tooltip({
placement: 'top'
});
$(".tip-right").tooltip({
placement: 'right'
});
$(".tip-bottom").tooltip({
placement: 'bottom'
});
$(".tip-left").tooltip({
placement: 'left'
});
}
initialize this with a document ready call:
$(document).ready(function () {
setUpToolTipHelpers();
});
This way I can determine the placement of the tool tip, and I only have to assign the tip with using a class and title:
<td class = "tip-top", title = "Some description">name</td>
Then I call, "setUpToolTipHelpers()" inside my success ajax function. Or you can call it on the complete function as well. This seems to work well for me.
run
$('#ding_me_tooltip').tooltip('dispose');
$('#ding_me_tooltip').tooltip();
after the ajax where #ding_me_tooltip is your selector

jquery ceases to work inside a reloaded div

So I am using something like this $('#msgs').load("<?php echo $_SERVER['REQUEST_URI']; ?> #msgs"); to reload a div which contains a table that allows for dynamic sorting by the user.
The problem I am facing is, not just the table run by tablesorter, but any other time I reload a div this way, any jquery functions that would normally operate in the div no longer function. Is there any way around this with out pushing the data?
$(function () {
$("#backups")
.tablesorter({
widgets: ['zebra'],
sortList: [
[1, 1],
[2, 1],
],
headers: {
6: {
sorter: false
},
}
})
.tablesorterPager({
container: $("#pager")
});
$('#create').click(function(e) {
$.ajax({
type: "GET",
url: '?process=create',
data: '',
success: function(data) {
$('#backups')
.load("<?php echo $_SERVER['REQUEST_URI']; ?> #backups");
}
});
e.preventDefault();
});
});
For example if I click the event #create, the div #backups reloads under which circumstances the tablesorter code for backups ceases to work.
UPDATE:
I created a fiddle that shows the issue. If you click the button, then the sorting abilities of the table no longer works. I'm a learn by example type person, and I'm not sure what to do with the below answers. Could someone perhaps show me using my fiddle how to fix it?
http://jsfiddle.net/1mfgfd2n/7/show/
The basic concept behind live events in jQuery is simple. Lets say you have HTML,
<div class="container"></div>
Now through AJAX or whatever means you prefer, you load a button inside this div.
$.get("url", function(data) {
$('.container').html('<button class="submit-something">Submit</button>');
});
If you have added the event handler on $(document).ready,
$(document).ready(function() {
$('.submit-something').click(clickHandler);
});
But when the document is ready, there is no button. This applies for any of the 'jQuery stuff' you want to do with the updated content. Unless, you have the element you are accessing via selector exists, jQuery can't do anything.
A possible generic solution (for events, there's live or on) is to add the 'jQuery stuff' inside the AJAX callback.
$.get("url", function(data) {
$('.container').html('<button class="submit-something">Submit</button>');
$('.submit-something').click(clickHandler);
});
You can always check at any point of time, whether the element exists or not by simply adding a console log.
console.log($('.submit-something').length);
Hope this answers your question regarding any jQuery operation you want to perform.
UPDATE:
load event is a special case that cannot be tested in this way. However, it is intuitive that the content inside the element where I called load event is cleared. So any event or tablesorter associated with it, no longer applies. Once the content is loaded, you need to associate the event or tablesorter again to the inner elements. This is same as getting a response from AJAX and rebinding the event.

Ajax request success handler

I have a json implemented page where I am displaying a list of videos. I am getting the video <embed> codes as a javascript. While in the loop of creating the list, I use the $.ajax jquery function to initialize the javascript to get teh video flash player. but the problem is that the player is not getting appended to the supposed <div>. Instead it gets appended at teh end of the document.
$.ajax({
url: item.ImagePath,
dataType: "script",
success: function(data){
alert(data);
var sResultFigure = $(document.createElement('figure')).append(result);
}
})
how do i solve this thing?
Well, you have to append it to the supposed div, like this:
var sResultFigure = $('<figure></figure>').append(result);
$('#supposedDiv').append(sResultFigure);
Assuming you are looping over divs and triggering an AJAX request for each div you could use the context parameter of the AJAX call to provide the current div to the success handler:
$('div.foo').each(function(index, div) {
$.ajax({
url: item.ImagePath,
dataType: 'script',
context: div,
success: function(data) {
// here $(this) points to the div over which we were looping
// when we triggered the AJAX request
$(this).append($('<figure/>').append(result));
}
});
});
i assume your div's id is "holder".
var sResultFigure = $("<figure></figure>").append(result);
$('#holder').append(sResultFigure);

Help me make a jquery AJAXed divs' links work like an iframe

I want to make a few divs on the same page work similar to iframes. Each will load a URL which contains links. When you click on those links I want an AJAX request to go out and replace the div's html with new html from the page of the clicked link. It will be very similar to surfing a page inside an iframe.
Here is my code to initially load the divs (this code works):
onload:
$.ajax({
url: "http://www.foo.com/videos.php",
cache: false,
success: function(html){
$("#HowToVideos").replaceWith(html);
}
});
$.ajax({
url: "http://www.foo.com/projects.php",
cache: false,
success: function(html){
$("#HowToProjects").replaceWith(html);
}
});
This is a sample of code that I'm not quite sure how to implement but explains the concept. Could I get some help with some selectors(surround in ?'s) and or let me know what is the correct way of doing this? I also want to display a loading icon, which I need to know where the right place to place the function is.
$(".ajaxarea a").click(function(){
var linksURL = this.href; //
var ParentingAjaxArea = $(this).closest(".ajaxarea");;
$.ajax({
url: linksURL,
cache: false,
success: function(html){
$(ParentingAjaxArea).replaceWith(html);
}
});
return false;
});
$(".ajaxarea").ajaxStart(function(){
// show loading icon
});
Assuming you want to listen to click events for all anchor tags inside all elements with class ajaxarea, then your selector works fine:
$(".ajaxarea a").click(function(){ .. });
And this line of code, while not a selector (you're just accessing a property on the DOM element that was clicked), should work fine as well:
var linksUrl = this.href;
As for ParentingAjaxArea, you'll need to use $(this).closest() with a selector to determine which parent you want, but it's hard to give a specific example without knowing your HTML structure. It looks like you want ParentingAjaxArea to be either the element with id #HowToProjects or #HowToVideos, so you could write:
var ParentingAjaxArea = $(this).closest("#HowToProjects, #HowToVideos");
As for the loading dialog, I think this answer explains a good method (using ajaxStart and ajaxStop).
Edit: I also noticed you're using the click event--If you plan on being able to attach event handlers to links that will be inserted into the DOM via AJAX later, look at delegate or live.
$(".ajaxarea a").live('click',function(e){
e.preventDefault(); //*
var URL = $(this).attr('href');
var parentFrame = $(this).parent(".ajaxarea"); //**
$.ajax({
url: URL,
cache: false,
success: function(html){
parentFrame.replaceWith(html); //***
}
});
});
* - added preventDefault to prevent click action (see e in function's arguments)
** - instead of closest, i used parent – like it more for it's descriptive qualities
*** - the var containing parent AJAX frame should be jQuery object, no need to wrap it in $(..)
This should work fine, but beware, it's untested.
edit:
You probably need a live (okay, I'm sure you need it). what click() does it's that it adds to all elements at the time in DOM an onClick event. What live() does, it's that it waits for any change in DOM and runs used selector (.ajaxarea a) again and if it fits for any of new elements, it adds the action. In pseudocode, it does basically this:
DOM.hasChanged{
$('selector').click(..)
}
I used this example for my own web page:
http://www.queness.com/post/328/a-simple-ajax-driven-website-with-jqueryphp
It works quite well and uses hash tags and jQuery.history.js for the history of your browser. It works very nice, because you can let something like a media player just continue playing. Take a look at my own site elsewise, where you can find the javascript file: ajaxpages.js. I haven't used live(), but maybe I should.
Figured it out! The problem was I was using the function ".replacewith()" which was removing my AJAXed div(class="ajaxarea") entirely instead of replacing the content. The proper function to use here was ".html()".
Here is my working code to make an AJAXed div work like an iframe:
//onload to initialize the div
$.ajax({
url: "http://www.foo.com/projects.php",
cache: false,
success: function(html){
$('#HowToProjects').html(html);
}
});
$(".ajaxarea a").live('click',function(e){ // must use live instead of .click()
e.preventDefault();
var URL = $(this).attr('href');
var parentFrame = $(this).closest(".ajaxarea");
$.ajax({
url: URL,
cache: false,
success: function(html){
parentFrame.html(html);
}
});
});

Categories

Resources