jQuery Tools -> Tooltip destroy method? - javascript

I am using Flowplayer's jQuery Tools framework (specifically the tooltips plugin) in a table, in addition to jQuery UI calendar.
Each row of the table has the ability to insert a row above and below it.
When doing this I am cloning the clicked object (events and objects) and inserting it directly above or below.
After adding a new row, I refresh the table, generating new id's for my elements, reinitializing the datepicker, and attempting to reinitialize the tooltip.
I am searching for a way to destroy it altogether from the instance and reapply it.
I am looking for something similar to the datepicker('destroy') method.
$j($editRow).find('input.date').datepicker('destroy').datepicker({dateFormat: 'mm-dd-yy', defaultDate : defaultDateStr});
I have already attempted to :
to unbind the mouseover and focus events : when reinvoking tooltip, it automatically goes for the object it was made from.
hide the tooltip DOM element, remove the tooltip object from the target, and reapply it. The same thing happens as (1)
Is there way I can create a destroy method myself?

I tried kwicher's method, and could not get it to work. Although I was trying to alter the minified code, and I'm not entirely sure I found the right place to make the change.
I did, however, get this to work. ValidationFailed is a class I am applying to all the input fields that are also having tooltips applied to them.
$('.validationFailed').each(function (index) {
$(this).removeData('tooltip');
});
$('.tooltip').remove();
I tried this several different ways, and this was the only combination that allowed me to add additional tool tips post-removal, without preventing the new tooltips from working properly.
As best I can tell, the tooltip class removal handles getting rid of the actual tooltip divs, whose events are also wired up directly. The .removeData allows the tooltip to be re-bound in the future.

Building on your ideas and Tom's answer, I found that three things are necessary:
remove the 'tooltip' data from the tooltip target element
unbind event listeners from the tooltip target element
remove the element (assuming you're using this tooltip approach to allow for arbitrary HTML in your tip)
So, this simple function should do the trick. Just pass it a jQuery object containing the target elements of the tooltips you want to destroy.
function destroyTooltips($targets) {
$targets.removeData('tooltip').unbind().next('div.tooltip').remove();
}

If you still need it you can do as follows:
- in the tooltip implementation file add the following function
destroy: function(e) {
tip.detach();
}
somewhere in :
$.extend(self, {
...
I have after the last native function.
Then when you want to remove the tip, fire:
$(.tip).data('tooltip').destroy();
It should do the trick
K

if($element.data('ui-tooltip')) {//if tooltip has been initialized
$element.tooltip('destroy');
}

Maybe it's too late... ;-)
But here you can find all methods of 'tooltip': http://www.w3schools.com/bootstrap/bootstrap_ref_js_tooltip.asp
I leave the tip for someone who could pass by, having the same problem: dealing with different 'tooltip' actions/objs.

Related

Dynamic field generation with CSS Togglebuttons and .on() binders

Question:
I am trying to build a dynamic form using jQuery. There are a few standard html form inputs in a row in addition to a CSS stylized "hidden checkbox" toggle button. (Example)
The first row is statically coded, and there is a button to add more rows to the form for batch submissions. JQuery applied to the .on(click) event works perfectly with the static content, but newly appended form rows ignore the binding. Even jsfiddle's dynamic display doesn't appear to function, though it is possible my fiddle example has a bug that my working copy doesn't have. (Fiddle)
/* activeToggle is the selector for the container and descendants,
// .toggleHappy is the hidden input element within activeToggle */
$(activeToggle).on("click", ".toggleHappy", function(e) {
e.preventDefault();
$(this).val(($(this).val() == 0) ? 1 : 0);
console.log($(this).val());
});
I have researched and found the common mistake of using .click() instead of delegating using .on(click, selector, fn()) and am thus using the latter now.
What is frustrating is I have another .on(click) that IS working with the dynamic content. (the remove function) So, I was hoping another pair of eyes might help me find out what my mistake is. I know this is very similar to other questions on the basic subject, but I have read quite a number of those discussions first, and have applied many of them to get where I currently am.
Updates:
I tried what Madhavan suggested and it does in fact work, but as expected, only for the first-child. So dynamically added rows are not pointed to. Thanks for the fast look. I feel like it might be a selector/scope issue, but whats weird is that once the page is loaded, I can type this directly into console and it works?
//this works run from console, but doesn't fire from a real click?
$(".theContainer .data .switch .toggleHappy").first().click();
ANSWER I have been working on another project in the interim and it is starting to look like .on(event, selector, fn) is not working at all for dynamically added items. But, I had a breakthrough! The other project was slightly simplified, and I found the following:
//.theContainer is static
//.data .switch .toggleHappy is the dynamic chain created
//does not delegate and bind dynamically
$(".theContainer").on("click", ".data .switch .toggleHappy", function() {});
//DOES work!
$(".theContainer").on("click", ".toggleHappy", function() {});
It would appear that a selector like .path .to .element only works well on existing static content, while .element allows .on() to be bound and delegated properly for dynamically generated nodes. See the updated fiddle.
The part that confused me was that hopping into the console and referencing dynamic elements with the full selector DID work on dynamic elements, but the events weren't delegated to them. Thanks again for the eyes that looked over this question, hope it helps someone else, because I still haven't found this on the web yet.
It appears that delegating jQuery events with .on() will only work on static content when the selector used within .on() is a list of consecutive elements. In my code, I had a single container which was static, I delegated an event to it referencing multiple elements between the container and the destination elements. It would work locally for any number of statically identified elements, but any dynamically added ones would ignore the bindings. It also would throw no errors, and it WOULD respond to lines of script executed within the console directly, using the same selector chaining as the function. I found the following:
//.theContainer is static
//.data .switch .toggleHappy is the dynamic chain created
//does not delegate and bind dynamically
$(".theContainer").on("click", ".data .switch .toggleHappy", function() {});
//DOES work!
$(".theContainer").on("click", ".toggleHappy", function() {});
It would appear that a selector like ".path .to .element" only works well on existing static content, while ".element" allows .on() to be bound and delegated properly for dynamically generated nodes. See the updated fiddle.
The part that confused me was that hopping into the console and referencing dynamic elements with the full selector DID work on dynamic elements, but the events weren't delegated to them. Thanks again for the eyes that looked over this question, hope it helps someone else, because I still haven't found this on the web yet.
$(activeToggle).on("click", function(e) {
e.preventDefault();
$(":first-child",this).val(($(":first-child",this).val() == 0) ? 1 : 0);
console.log($(":first-child",this).val());
});
I made a change like this and works fine. But I'm not sure why it is not triggering for '.toggleHappy' instead.

jQuery: Get elments with custom attribute that has hidden child, add live hover function

I wanted to get all elements that has a specific attribute and has a child of a specific type that is hidden. To do this, I wrote this selector:
$("*[custom-attr]:has('span:hidden')")
In addition to this, I wanted to add a live function on hover. For example like this:
$("*[custom-attr]:has('span:hidden')").live("hover", function() { /* do something */ });
I thought this was working properly, since I got the visual result I wanted. However, when using Firebug, I noticed that it was probably not perfect. When moving the mouse within the body, even if not hovering the elements that were meeting the selection, Firebug indicates that the HTML elements hovered are affected (they appear as yellow in Firebug HTML tab). See attached image:
Why is this and how can I avoid it?
I noticed that a similar selector did not cause the same behavior, like this one to get elements without the span child:
$("*[custom-attr]:not(:has('span'))").live("hover", function() { /* do something */ });
Thanks.
Try using natural browser selectors and that way avoid jQuery adding temporary attributes. For your case, instead of has() you can use:
$("[custom-attr]").on("mouseenter", function() {
if ( $(this).find('span:hidden').length ) {
/* your code */
};
});
Since you're getting the visual results you are expecting, it sounds like it's working. I think Firebug simply highlights elements that have recently had something change on itself or, if collapsed in the HTML view like on your screenshot, somewhere among its children. This highlighting will happen both when e.g. an attribute is change and when the change is reverted on e.g. mouseleave, and the highlighting will stay for some time after the change has occurred.
That said, it's also a good idea, as Kartikeya mentioned in a comment, to switch from .live(), which is deprecated, to .on().

Use custom function to create elements in d3.js

I want to use d3.js to interact with marked text in CodeMirror. However, to mark text in CodeMirror, you call markText(from,to, {class: 'my-class'}) and it creates a span around the text with class my-class.
I wish to mark many pieces of text based on data and then add some event handling and such to them. Thus, I would like to do something like:
var box = d3.selectAll('box').data(myData);
box.enter().each(function(d) {cm.markText(from(d), to(d), {class: 'box'});})
box.on('mouseover', function(d) {...});
box.exit().remove();
However, d3's enter selections only support append, insert, and select. I tried faking the effect with select already (e.g. box.enter().select(arbitraryElt).each(...)) but that didn't work.
Of course, I could just loop through my data, mark the text, and then use d3 to apply the other attributes I want, but that sort of defeats the point of using d3.
Is it possible to do this with d3 in an elegant way?
EDIT:
I realized I completely misunderstood how markText works, and thus the context of my question is invalid. However, I'm still curious if it's possible to create elements using an arbitrary function instead of append.
You can use .call for custom functions, so that would be .call(box).
You can also use insert(), but not arbitrary functions. The problem is that the elements in the enter() selection don't really exist yet (i.e. there're no corresponding DOM elements). As there are no DOM elements, you can't operate on them.
More information in the documentation. You could of course implement your own custom function for handling the enter() elements, but that would require quite some knowledge on how d3 works internally.

Easy way to bind dynamic elements without having to recall functions jquery

I currently have a page in which users can drag content around, resize it, etc.
The basic structure looks like the following:
$('.element').on().resizable().draggable();
When called at the beginning of the document load it adds bind events, resizable and draggable. Now the problem I have is that a user can add in new elements dynamically. These new elements are no longer covered by the above code. What I ended up doing is the following:
function bindEvents(){
$('.element').on().resizable().draggable();
}
bindEvents();
And then when elements are added I turn off the current implementation and then turn it on again so that it will include the new elements:
$('.element').off().resizable("destroy").draggable("destroy");
bindEvents();
No I know this is incredibly inefficient and most likely uses way more memory than needed. My question is, is there a better way to do this? Is there a way to add the one particular element to the already established group of bound elements?
Thanks!
If you don't want to waste work on the old items then brand them with something and avoid them later, or vice versa.
function bindEvents(){
$('.element').not('.initialized').addClass('initialized')
.on().resizable().draggable();
}
Why not use the delegation functionality of on() and bind to a container of the elements?
$('#container').on('mouseover', '.element', function(e) {
$(this).resizable().draggable();
});
You'd want to add the styling for the draggable classes to be there by default, but this is easily accomplished by adding the ui-resizable class to the elements:
<div class="element ui-resizable">Foo</div>
Any elements that match the filter ('.element') will automatically get the functionality when they are added to #container

qTip (jQuery plug-in) how can I remove all qtips in my page?

I'm using the jquery-plugin qTip. What's the command to destroy all tooltips in my page ?
I tried:
$('.option img[title], span.taxonomy-image-link-alter img[title]').qtip("destroy");
But it didn't work...
Thanks
I've solved with $(".qtip").remove();
qTip2 is newer version of this script, but I would just like to point out 1 thing.
$(".qtip").remove();
This piece of code didn't destroy all the tooltips - it simply removed their containers. All the handlers and events attached to objects which invoked the tooltips are still avaiable in browser's memory.
In qTip to delete the tooltip and it's handler scompletely you would have to use:
$(mytooltip).qtip("destroy");
or
$(mytooltip).qtip('api').destroy();
In qTip2 however using this:
$(mytooltip).remove();
Would automaticaly call out the api and destroy tooltip and it's handlers completely.
$('.qtip').each(function(){
$(this).data('qtip').destroy();
})
qtip("destroy") is buggy (version 2.1.1) and doesn't clear everything.
I found this as a proper workaround:
// don't call destroy if not needed
if (element.data("qtip")) {
// the 'true' makes the difference
element.qtip("destroy",true);
// extra cleanup
element.removeData("hasqtip");
element.removeAttr("data-hasqtip");
}
Looks buggy. I've had some luck with this, but it does not restore the original titles. I suspect destroy doesn't do that either...
$('span.taxonomy-image-link-alter img')
.filter(function(){return $(this).data('qtip');})
.qtip('destroy');
It seems you cannot call destroy on elements without qTip - it doesn't fail silently, but throws an exception and stops the loop.
I experienced that the api-call
$(selector).qtip('destroy')
doesn't remove all qtip-data dependably, especially when using several qtips simultaneously.
In my case I had to remove a visible qtip and successfully used this workaround:
$(selector).removeData('qtip');
$('.qtip :visible').remove();
What about:
$('[data-hasqtip]').qtip('destroy', true);
Seems to be working with qTip2 version 3.0.2.
if ( jQuery( '.qtip' ).length > 0 )
{
jQuery( "#IdElement").qtip("destroy");
}
None of these answers helped me.
In my case, I had a qtip on an element with a close button. The close button removed the element, so there was no reference point to remove the qtip after the element was removed.
I thought $('.qtip:visible').remove() would work, but it somehow removed all of the qtips on the page, and not the single one that I wanted removed.
I noticed that the visible qtip is given a class qtip-active, so what worked for me was:
$('.qtip-active').remove();
It may be a little late, but I had issues with memory and page load when an ajax call replace the content in the page, deleting the target qtip2 objects before destroy them, so some elements remains even if the target had gone.
Based on the fact that sometimes you want to clean all qtips2 elements and data, no matter if the original object exist or not, some tooltip elements remains on the body, so when the original target has gone there is no easy way to call the destroy() method.
Unless you do it searching for the created objects instead of the targets.
jQuery('div[id^="qtip-"]').each(function(){ //search for remaining objects
_qtip2 = jQuery(this).data("qtip"); //access the data where destroy() exist.
//if it's a proper qtip2 object then call the destroy method.
if(_qtip2 != undefined){
// the "true" is for immediate destroy
_qtip2.destroy(true);
}
//if everything went right the data and the remaining objects in the body must be gone.
});
I used JQuery for a no conflict issue, but you can use "$" (symbol) instead of JQuery

Categories

Resources