0

I'm using the qtip extension for ctyoscape.js to add qtips when I click nodes.

Dependencies:

  • cytoscape-2.5.0
  • jquery-2.1.4
  • jquery-ui-1.11.4
  • cytoscape.js-qtip
  • qtip2-2.2.0

The problem I'm having is that it's not working correctly I use an anonymous function to assign the qtip content.

If I assign the content statically, it works fine:

 this.cy.elements().each().qtip({           
    content: {
        text: "some text", 
        title: "some title", 
        button: true
    },

    /*other options*/
});

enter image description here

If I assign it dynamically:

this.cy.elements().each().qtip({    

    content:{
            text: function(event, api) {
                return "some text"  + this.data().properties.id;;
                },
            title: function(event, api) {
                return "some title" +  this.data().properties.id;;
            },
            button: true                            
    },

    /*other options*/
});

enter image description here

It's referencing the element object correctly, but for some reason it doesn't create the title or button. The title function callback is never used.

Any suggestions for why this is is happening?

Clue 1:

If I step out from the function callback, in jquery.qtip.js, lines 1027 and 1028:

if($.isFunction(contentOptions.text)) { this._updateContent(contentOptions.text, FALSE); }
if($.isFunction(contentOptions.title)) { this._updateTitle(contentOptions.title, FALSE); } 

For the static text and title, contentOptions.text = 'some text' and contentOptions.title = 'some title'.

For the dynamic text and title, contentOptions.text = function(), while contentOptions.title = false.

How/why has the callback been lost for the title?

Clue 2:

If I remove the anonymous function for text but keep for title, the title callback will be used, however, this does not reference the cytoscape element object, it references the qtip div.

    content: {
        text: "some text", 
        title: function(){ return "foo" + this.data().properties.id;}, //<-- will error because this.data() is not a function.
        button: true
    },
dwjohnston
  • 11,163
  • 32
  • 99
  • 194
  • If you log `this.data().properties.id` within the title function, is it null? I don't think the `this` is the `this` you want at that point so to speak. – Gerrat Dec 17 '15 at 21:54
  • @Gerrat The title function callback is never fired. – dwjohnston Dec 17 '15 at 22:02
  • Just to be clear, by `never fired`, you're saying that this: `title: function(event, api) { return "some title" }` does not work either? – Gerrat Dec 17 '15 at 22:08
  • @Gerrat That's correct. – dwjohnston Dec 17 '15 at 22:11
  • There's something else going on. Your answer proves the function is fired/called. – Gerrat Dec 17 '15 at 22:15
  • @Gerrat - See my update to the question. For some reason assigning a callback to `text` prevents the `title` callback from being used. You're right about `this` is different in that context. Anyway - the problem is solved, if not understood. :) – dwjohnston Dec 17 '15 at 22:19

2 Answers2

0

I'm happy for someone else to post an answer to explain why this works, but the solution is to set everything using the qtip api object, within the text callback:

    content:{
            text: function(event, api) {

                api.set('content.title', "some title" +    this.data().properties.id);
                api.set('content.button', true);
                return "some text"  +  this.data().properties.id;
                }                   
    },          

I imagine what this is about, is something like the callback being fired on some kind of 'create qtip' event, and because there is only one of these events only the text callback is fired. (That doesn't really make sense to me but..).

dwjohnston
  • 11,163
  • 32
  • 99
  • 194
0

I think your issue has to do with closures. You need to capture the this at the time. I think something like the following will solve your issue (untested):

title:  function(elem) {
    return function(event, api) {
        return "some title" +  elem.data().properties.id;
    }
}(this), 

The way this works is that the outer function is called immediately, and captures your this variable in the parameter, elem. The inner function is then returned & you can use elem like you wanted to use this

Gerrat
  • 28,863
  • 9
  • 73
  • 101
  • This solution has the right sort of explanation. The extension is *on top* of Qtip. It can't and shouldn't re-implement every feature of Qtip in the extension; otherwise it may as well just implement its own tooltips instead of Qtip... I know it supports the top-level `content` with a function on the graph element, so the user should be calling `content: function( ele ){ return { title: ..., text: ... } }` – maxkfranz Dec 21 '15 at 16:15