0

Site consists of 3 pages, index.html, 1.html, 2.html.
The goal is to load html from 1.html which contains tooltip and some other htmls and display it in a div, after mouseover on the loaded tooltips I want tooltip texts to be fetched from 2.html.
However this code does not works, no error is shown and AJAX is never executed.

$(document).ready(function(){
    $( ".content span" ).tooltip({
        track:true,
        open: function( event, ui ) {
              var id = this.id; 
              var userid = $(this).attr('data-id');
              
              $.ajax({
                  url:'2.html',
                  type:'post',
                  data:{userid:userid},
                  success: function(response){
                      $("#"+id).tooltip('option','content',response);
                  }
              });
        }
    }); 
});
.container{
    margin: 0 auto;
    width: 30%;
}

.content{
    border: 1px solid black;
    padding: 5px;
    margin-bottom: 5px;
}
.content span{
    width: 250px;
}

.content span:hover{
    cursor: pointer;
}
<!doctype html>
<html>
    <head>
        <title>Dynamically show data in the Tooltip using AJAX</title>      
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> 
        <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>      
    </head>
    <body>
    <input type="button" id="btnLoad" value="Load"/>
        <div class='container' id="container"></div>
    </body>
<script>
$( "#btnLoad" ).click(function() {
$.ajax({
  url: "1.html",
  context: document.body
}).done(function( msg ) {
    $('#container').html(msg);
    $(this).tooltip();
  });
});
</script>
</html>

Sample HTML of 1.html file

            <div class='content'>
            <span title='Please wait..' data-id='1' id='user_1'>Pepsi</span>
        </div>

        <div class='content'>
            <span title='Please wait..' data-id='2' id='user_2'>7 Up</span>
        </div>

Sample HTML of 2.html file

This Tooltip text will be replaced with texts from Database
Sourav
  • 17,065
  • 35
  • 101
  • 159
  • `$(".content span").tooltip({` only works on elements that exist at the time the code runs - so you need to run this after you add new elements. – freedomn-m Apr 10 '22 at 15:06
  • @freedomn-m Please guide how to do so – Sourav Apr 10 '22 at 15:51
  • Does [this](https://stackoverflow.com/questions/22440725/tooltip-on-dynamic-created-content-in-jquery) work for you? See [API doc](https://api.jqueryui.com/tooltip/), it's about using event delegation. – vee Apr 10 '22 at 15:51
  • After your code that "*JS scrips loads content from this PHP code*", add the same code that starts with `$(".content span").tooltip({` – freedomn-m Apr 10 '22 at 18:26
  • @freedomn-m It does not work :( – Sourav Apr 12 '22 at 03:09
  • @vee Sorry but that does not works for me – Sourav Apr 12 '22 at 03:18
  • 1
    Your next step then is to provide a snippet that includes your initial tooltip setup and then some dynamically loaded html (after the initial tooltip setup). See [mcve]. As it is, you've not shown when/how (the js) you load your "dynamically loaded html". It's not clearly you actually have "dynamically *loaded* html" - ie HTML loaded via ajax after the page has loaded - but rather might be dynamically *generated* HTML - a snippet will show us what you're doing. – freedomn-m Apr 12 '22 at 08:09
  • Though I may also be misreading your problem - your title is "dynamically loaded *html*" - but your question is "dynamically loaded *content*" where the content is html - so is the issue that your tooltip works, but not when the content of that tooltip is loaded dynamically? (rather than not being applied to late-loaded html) – freedomn-m Apr 12 '22 at 08:12
  • It would be useful to see the *rendered* html that you're applying the tooltip to, as well as a response from the tooltip ajax. – freedomn-m Apr 12 '22 at 08:14
  • @freedomn-m Please check ! – Sourav Apr 13 '22 at 18:24
  • in simple -> A button on index.php loads content from news.php, and on this content I want tooltip, the tooltip should load content from info.php?id= – Sourav Apr 14 '22 at 06:45
  • @freedomn-m I've tried to make the question cleaner, plz check – Sourav Apr 23 '22 at 13:29
  • @vee I've used code snippets to make the question cleaner, plz check – Sourav Apr 23 '22 at 13:29

2 Answers2

4

UPDATED

Your updated question is considerably clearer, and helped me track down what is happening. My original answer solved one of the issues, but not all. There are actually a series of problems.

Problem 1

The first problem is the one I previously described: jQuery selectors only match page elements that exist at page load. $(".content span").tooltip() will only initialise tooltips for spans that exist inside .content at page load. If you inject new spans later (or new .contents with spans inside them), they are not included, and they won't have tooltips.

The simplest fix is to use the (apparently undocumented?) selector tooltip option. Initialise the tooltips on an HTML element which exists at page load, and then use the selector option to filter to only match the elements you really want to have tooltips on. The key is the filtering part happens live, and so will match newly added elements.

In your case, we can't use .content for the tooltip, since that does not exist at page load either. We need some parent element which exists on the page before any of your AJAX stuff happens. Let's assume you have a parent like <div class="parent">, and your HTML will be injected into that (I guess you could also use body or document). So we initialise the tooltips on that parent div:

$(".parent").tooltip({
    // the selector option filters the elements that will actually have tooltips
    selector: '.content span'
});

Problem 2

Now we have basic tooltip functionality working, even for new content injected in to the page. The next step is to dynamically load content over AJAX, and update the tooltip's title with that content. Normally you would do that like this:

$(selector).tooltip('option', 'content', 'New tooltip text!');

where selector is something matching the individual span we're currently viewing the tooltip for. But in our case, that won't work - that span has no tooltip attached! Because we're initialising tooltips on .parent, the individual spans where the tooltips show up do not have a tooltip attached, and calling .tooltip() on them will fail with an error like:

cannot call methods on tooltip prior to initialization; attempted to call method 'option'

To reference the existing tooltip, we need to do $('.parent').tooltip(), but if we do:

// Don't do this
$('.parent').tooltip('option', 'content', 'New tooltip text!');

It would change every tooltip on the page to the same 'New tooltip text!', and we don't want that.

The .open event handler you are using to fire your AJAX receives the jQuery event as a parameter. And that event includes info about the currently targeted element. Using that, we can find which span on the page we are really currently looking at:

open: function(event, ui) {
  // Find real targeted tooltip
  let target = $(event.originalEvent.target);

So now we can manipulate that element's title:

$target.attr('title', 'New tooltip!');

We can also make it a tooltip!

$target.tooltip();

In fact this is not enough, because the .parent tooltip is already open and showing "Please wait ...". The above steps do update the title, but you have to move your mouse away and then back to see it. We want the content to refresh immediately, live. I tried some experimentation and found this works well:

// Temporarily disabling the parent tooltip hides the one that was already open
$('.parent').tooltip('disable');

// Update our target's title
$target.attr('title', 'New tooltip!');

// Initialise a tooltip on our target, and immediately open it
$target.tooltip().tooltip('open');

// Re-enable the parent tooltips, so this process will work again for other spans
$('.parent').tooltip('enable');

So we are actually adding new tooltip instances to the page, each time we mouse-over a matching span. This approach has the added advantage that the new tooltip replaces the old, parent one for the specific span. That means the parent tooltip options no longer apply to spans that have already had their tooltip content loaded, which means if you mouse-over it a 2nd time, it does not fire the AJAX request a 2nd time for that span. The content we got from the first AJAX call is already there and simply re-used.

Here's a working snippet demonstrating all of this.

I've used https://www.npoint.io/ which is a JSON storage bin, to simulate your AJAX calls. I have no affiliation with it, it just seems like a handy tool. Unfortunately it does not seem very reliable, and requests to it failed a few times while I was working. If that happens, pls retry.

I added a few bins with data matching your 1.html and 2.html files, the code below loads them and uses their content:

  • This bin includes your HTML content;
  • This bin includes dummy data for user ID 0;
  • This bin includes dummy data for user ID 1;
  • This bin includes dummy data for user ID 2;

$(document).ready(function () {

    // This URL returns a JSON response including HTML like your 1.html,
    // this way we can realistically simulate your 1.html AJAX call.
    let htmlContentUrl = 'https://api.npoint.io/6893d2fd7632835742cf';

    // These URLs return JSON responses including plain text like your
    // 2.html file, this way we can realistically simulate AJAX calls 
    // loading and using data from your DB
    let userContentUrls = [
        'https://api.npoint.io/06cf752b395286e41cb4',
        'https://api.npoint.io/2a3e0a338f92a803b3fc',
        'https://api.npoint.io/a9a4296244c36e8d5bfc'
    ];

    // We use this selector a few times, it is good practice to cache it
    var $parent = $('.parent');

    $("#btnLoad").click(function () {
        $.ajax({
            url: htmlContentUrl,
        }).done(function (msg) {
            $('#container').html(msg.content);
        });
    });

    $parent.tooltip({
        selector: '.conten span',
        track: true,
        open: function (event, ui) {
            // Find real targetted tooltip
            var $target = $(event.originalEvent.target);
            var userid = $target.attr('data-id');
            url = userContentUrls[userid];
            console.log('For userid', userid, 'url is', url);

            $.ajax({
                url: url,
                type: 'get',
                data: {
                    userid: userid
                },
                success: function (response) {
                    // We can't simply update the tooltip for $target, because
                    // it *has* no tooltip!  The tooltip is actually attached
                    // to .parent.  To refresh the already visible tooltip, we
                    // need to take a few steps.
                    $parent.tooltip('disable');
                    $target.attr('title', response.content);
                    $target.tooltip().tooltip('open');
                    $parent.tooltip('enable');
                }
            });
        }
    });
});
.container {
  margin: 0 auto;
  width: 30%;
}

.content {
  border: 1px solid black;
  padding: 5px;
  margin-bottom: 5px;
}

.content span {
  width: 250px;
}

.content span:hover {
  cursor: pointer;
}
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<div class="parent">

  <div class="container">
    <div class="content">
      <span id="user_0" title="Please wait ..." data-id="0">Water</span>
    </div>
  </div>

  <input type="button" id="btnLoad" value="Load" />

  <div class='container' id="container"></div>

</div>

Side notes:

  • I added a tooltip (user ID 0) which is visible on page load, just to demonstrate everything is working both on page load and after new content is injected;

  • Convention is to use GET when retrieving data, and POST for changing data. Your AJAX calls are just retrieving data to display, so really should be GET;

  • I wasn't sure why you had context: document.body, but I don't think it is necessary, and to keep things simple I removed it;

  • If you are going to use a jQuery selector more than once, it makes sense to cache them. I did that for $parent, and $target.

Don't Panic
  • 13,965
  • 5
  • 32
  • 51
  • Thnx for your great reply, but sorry it did not helped. My question was "A button on index.php loads content from modal.php, and on this content I want tooltip, the tooltip should load content from tooltip.php?pid=" Your ans does not load anything from the 3rd page. – Sourav Apr 20 '22 at 18:32
  • Because that is not relevant to the problem you have ... The tooltips don't work, because they are injected dynamically. Whether you load tooltip content via AJAX or not is not relevant to the problem. Once you get tooltips working, they will load your content via AJAX. Did you try either fix I described? – Don't Panic Apr 21 '22 at 20:27
  • I tried that, but it justs shows "Loading..." , the AJAX is not fired – Sourav Apr 22 '22 at 04:10
  • What is the purpose of the `.mouseout()` code? It will remove the tooltip you just loaded, so it has to be re-loaded again later. I guess the tooltip contents can change, so must always be fresh? – Don't Panic Apr 23 '22 at 08:23
  • Tooltip contents doest not change. – Sourav Apr 23 '22 at 09:07
  • I'll try again - What is the purpose of the `.mouseout()` code? – Don't Panic Apr 23 '22 at 09:29
  • to hide the tooltip – Sourav Apr 23 '22 at 09:30
  • I'm confused. Tooltips are hidden when you mouseout by default, you don't need to add code to do that ... I mean that's what a tooltip *is*, something that is shown on mouseover, and hidden on mouseout. You can see this in my example ... Is that really the only reason you have that code? What happens if you remove it? – Don't Panic Apr 23 '22 at 09:53
  • Removing that block of code does nothing. – Sourav Apr 23 '22 at 13:11
  • I've made the question cleaner by using code snippets, give it a chance. – Sourav Apr 23 '22 at 13:30
  • thnx a ton buddy ! – Sourav May 02 '22 at 18:02
  • Why this does not work for mobile ? It keep showing "Please wait ..." @Don'tPanic – www.friend0.in Aug 17 '22 at 16:39
0

Can you try to push this line to your code.

$('body').tooltip({selector: '.content span'});

Right after

$(document).ready(function() {
    // push the above line here
    ... your current code

}
Quân Hoàng
  • 371
  • 3
  • 9
  • The problem is more than just selector, I want some ajax action on this too, unfortunately which does not get fired :( – Sourav Apr 20 '22 at 18:35
  • this is because of the New DOM is not binding the function tooltip. So can you try to push $('body').tooltip({selector: '.content span'}); at the line after the Ajax call done? – Quân Hoàng Apr 21 '22 at 04:15