Attributes / vars in tooltipster are ignored - javascript

I've been trying for two days to figure out why tooltipster (which is great btw) is not taking into account any var declared in the javascript / head section. For instance:
<script>
$(document).ready(function() {
$('.tooltip').tooltipster({
var data = 'toto';
contentAsHTML: true,
animation: 'slide',
delay: 100,
content : $(data)
});
});
</script>
with:
<img src="Pics/winter.png" alt="winter" border="1" class="tooltip" />
is not working at all (meaning the tooltip is not showing up in the HTML page). I tried several coding variations, including adding ' ; ' etc. but it doesn't change the result.
I also tried to get an element's attribute using:
content : '$(this).attr('alt')'
which is my final goal, and it doesn't work either. What am I missing?

The most probable reason is
var data = 'toto';
contentAsHTML,animation,delay,content etc are options that tooltipster accepts.
But when it is coming across var data = 'toto'; it will through an error since it is not an option which tooltipstercan accept

I've made a quick jsFiddle to demo the "correct" way of setting the content of the tooltip from the originating element - on it's intialization.
The reason this wasn't working before was due to:
You declaring the variable data within the JSON object passed to the tooltipster function - this is invalid syntax for JavaScript.
Your second attempt was closer, but using this in the content property is an ambiguous reference to an "outside" this scope - likely unrelated to the tooltipster instance or HTML node you were after.
Here's the amended code that should do what you want:
$(document).ready(function() {
$('.tooltip').tooltipster({
contentAsHTML: true,
animation: 'slide',
delay: 100,
functionInit: function(instance, helper) {
var alt = $(helper.origin).attr('alt');
instance.content(alt);
}
});
});
I hope this helps :)

Related

How to place a custom control inside the map div in ol3?

I'm sorry, this question is irrelevant to ol3 and there were some evident code errors (Note from the author)
I'm rewriting a Ol 2 map application with the most recent version of Openlayers 3.15.1. I need to add custom controls to manipulate sea surface temperature maps. I want to place the custom controls over the map . However after trying to recreate the code of some examples showing how to write custom controls with Ol3, I have found some drawbacks to correctly recreate it.
The custom control is composed by a small icon and clicking over it does some stutf. Here below I show several versions of the code used. Basically the controls are created by a function that loads initially.
Only one of them works properly and I would like to understand why the others do not. All examples are almost equivalent two are with pure javascript and two with JQuery trying to look for a optimal solution.
Code 1: Pure Javascript but using innerHTML to insert the image into a . The image seems to be not inserted into the DOM.
var texto = "<img id=\"tool_draw\" src=\"/js/Saidin/Image/draw_line_off.png\">";
var element = document.createElement('div');
element.innerHTML=texto;
element.className = 'ol-unselectable ol-mycontrol';
element.style.position="absolute";
element.style.width="24px";
element.style.top= "70px";
element.style.left= "9px";;
var action= function(e){ alert('hola'); }
document.getElementById("tool_draw").addEventListener("click", action, false);
var okk= new ol.control.Control({
element:element
});
map.addControl(okk);
This code does not work. The error is: document.getElementById(...) is null
Code 2: Pure Javascript but creating the image with the constructor and that's all!
var texto = "/js/Saidin/Image/draw_line_off.png";
var boton = document.createElement('img');
boton.src=texto;
boton.className = 'ol-unselectable ol-mycontrol';
boton.setAttribute("id","tool_draw");
boton.style.position="absolute";
boton.style.top= "70px";
boton.style.left= "9px";
var action= function(e){ alert('hola'); }
boton.addEventListener("click", action, false);
var okk= new ol.control.Control({
element:boton
});
map.addControl(okk);
This code works fine !
Code 3: I think is Equivalent to Code 1 but using JQuery library
var texto ="<img id=\"tool_draw\" src=\"/js/Saidin/Image/draw_line_off.png\">";
$('body').append($('<div/>', {
id:'hola',
'class' : 'ol-unselectable ol-mycontrol',
texto:texto,
css: { "position":"absolute","top": "70px", "left":"9px" }
}));
element=$('#hola');
var cont= function(e){ alert('hola'); }
$("#tool_draw").on('click', cont );
var okk= new ol.control.Control({
element:element
});
map.addControl(okk);
This code does not work. The error is: TypeError: Argument 1 of Node.appendChild does not implement interface Node..
Code 4: I think is equivalent to Code 2 but using JQuery library
var element=$('<img>', {
id:'tool_draw',
src:'/js/Saidin/Image/draw_line_off.png',
'class' : 'ol-unselectable ol-mycontrol',
css: { "position":"absolute","top": "70px", "left":"9px" }
});
$('#map').append(element);
var cont= function(e){ alert('hola'); }
element.on('click', cont );
var okk= new ol.control.Control({
element:element
});
map.addControl(okk);
This code works fine ! but... the same error from ol.js appear TypeError: Argument 1 of Node.appendChild does not implement interface Node.
Can somebody explain me what's wrong with the failing codes ?. I apologize for this long question and I'm not sure if the problem comes from JQuery, JavaScript or is related with the new OL3 version. Any explanation is welcome !. Thanks
code1 doesnt work cause you use getElementById while the element is not ready on dom. You may use element.addEventListener("click", action, false); but I am not sure if it would work.
Code 2 works cause you attach the listener directly to the element (like the way I suggest on 1) and you are not searching for it in the DOM (getElementById)
Code 3 doesnt work cause appendChild is a native DOM method and only accepts DOM nodes as a parameter. The element you're trying to append ($('body').append($('<div/>'.....) is a jQuery object, not a DOM element.
Code 4 shouldnt work for the same reason as 3.
Your problems have nothing to do with ol3. It is jquery & js problems. Hope I helped you a bit

Change javascript variable in seperate element

I run a WoW guild forum based on php (phpbb), javascript and html. Ever since long, Wowhead allows links to be posted to their item/spell IDs etc. The basic code to the Wowhead JS and it's variables is:
<script src="//static.wowhead.com/widgets/power.js"></script>
<script>var wowhead_tooltips = { "colorlinks": true, "iconizelinks": true, "renamelinks": true }</script>
There is an extension that puts this code in the footer of every page via a HTML file. Every Wowhead link posted will be converted in a link with a tooltip explaining what it links to. The '"renamelink": true' portion of the wowhead_tooltips variable makes it as such that any link of an item or spell is renamed to the exact name of what it is linked to.
The problem: when I generate custom URLs using a Wowhead link, ie:
Teleport
instead of displaying 'Teleport' with a tooltip of Blink, it will rename the entire URL to Blink with an icon, as described in the wowhead_tooltips variable.
What I want to achieve is:
Any direct URL to Wowhead should be converted into a renamed spell/item.
Any custom URL to Wowhead should be retain it's custom text, but retrieve the tooltip.
This should both be possible on a single page.
The best solution I have come up with is to add an 'if' function to var wowhead_tooltips based on class, then add the class to URLs:
<script>if ($('a').hasClass("wowrename")) { var wowhead_tooltips = { "colorlinks": true, "iconizelinks": true, "renamelinks": false } }</script>
<a class="wowrename" href="http://www.wowhead.com/spell=1953">Teleport</a>
This works, however, the problem with this solution is that once the script recognizes one URL with the class "wowrename" on the page it will stop renaming all links, meaning that custom URLs and direct URLs can't be mixed on a single page.
Any other solution I've tried, using IDs, defining different variables etc either don't work or come up with the same restriction.
Hence the question, is it possible to change Javascript variables (in this case "var wowhead_tooltips { "renamelinks": false}" per element (URL), based on id, class or anything else?
Direct link that gets renamed with tooltip and iccn.
Teleport
Custom link with tooltip and original text.
I've stored the original link text as a data attribute so we can restore it after it's been changed.
<a class="wowrename" href="http://www.wowhead.com/spell=1953" data-value="Teleport">Teleport</a>
Keep checking for when static.wowhead.com/widgets/power.js changes the last link text. Once changed, restore using the data-value value, remove the styling added that creates the icon and stop the timer.
$(function () {
//timmer
checkChanged = setInterval(function () {
// check for when the last link text has changed
var lastItem = $("a.wowrenameoff").last();
if (lastItem.text() !== lastItem.data('value')) {
$("a.wowrenameoff").each(function () {
//change value
$(this).text($(this).data('value'));
//remove icon
$(this).attr('style', '');
//stop timer
clearInterval(checkChanged);
});
}
i++;
}, 100);
});
This does cause the link icon to flicker on then off, but it is repeated after a page refresh.
JSFiddle demo
This is simple solution. It's not the best way.
var wowhead_tooltips = { "colorlinks": true, "iconizelinks": true, "renamelinks": true }
$('a').hover(function() {
if ($(this).hasClass('wowrename') {
wowhead_tooltips.renamelinks = true;
}
else {
wowhead_tooltips.renamelinks = false;
}
});
I don't know how exactly wowhead API works, but if wowhead_tooltips variable is loaded exactly in the moment when the user points the link with the mouse (without any timeout) - this can fail or randomly work/not work.
The reason can be that the javascript don't know which function to execute first.
I hope this will work. If it's not - comment I will think for another way.
You have to loop on all the links, like this:
$("a.wowrename").each(function() {
// some code
});

scriptaculous blindUp/blindDown issue

I wrote a little script that observes clicks and blinds up/down according to the 'display' property, and also added a queue-to-end parameter to the blindUp in order to avoid even more serious display issues. This is obviously not the way to implement this, as display bugs appear if click events are invoked in the middle of the effect.. This is the code:
<script type="text/javascript">
$$('#leftnav_container #modules h2').each(function(El){
El.observe('click',function(){
container = this.next('div');
display = container.getStyle('display');
if(display == 'none'){
container.blindDown({duration: 0.3});
}else{
container.blindUp({duration: 0.3, queue: 'end'});
}
})
});
</script>
Again, the problem is that I rely on 'display'. What is the proper way to this?
This should simplify it
$$('#leftnav_container #modules h2').invoke('observe','click',function(){
container = this.next('div');
Effect.toggle(container , 'blind', { duration: 0.3 });
});
Firstly if you are only running one method on all elements in the array returned from $$() then you can use the PrototypeJS method invoke().
http://api.prototypejs.org/language/Enumerable/prototype/invoke/
Then Effect.toggle() will check if the element is visible and do the appropriate up/down effect.
Try this out and let me know if it works for you.

Chrome not returning hash value

I'm using the following snippet if jQuery JavaScript to return a hash value at the end of a URL. It works perfectly in FF but the alert on line 4 returns empty in Chrome.
Seems like the window.location.hash.substring(1) line does not work. I have also tried window.location.hash.replace("#", "");
// Map Clicks
$("#tab2.tab_content #map").delayed('click', 500, function() {
state = window.location.hash.substring(1);
alert(state);
jsonLink = 'http://ml.uscm.org/ministries.json?state=' + state + '&active=true&callback=?';
getMapResults();
return false;
});
What's the trick to retrieving a hash value from the URL in Chrome?
The URL is built like this :
http://www.ourdomain.com/thispage.html#IL
Where IL is a two letter abbreviation for a state. I want to get the "IL".
I have a working demo here:
http://richcoy.com/locator/index2.html
Click on the Search by State tab in Chrome then click on a state and you'll see the issue. The browser shows that the url that it wants to go to is built correctly. –
Thanks.
You may want to try this instead:
$(window).on('hashchange', function() {
console.log(window.location.hash.substring(1));
});
The click event triggers before the hashchange event so you can't rely on your map click implement (even if you delayed it).
Supported browsers list for hashchange: http://caniuse.com/hashchange
In case you don't have to use hash, here is a simpler solution:
$("#tab2.tab_content #map a").click(function() {
console.log($(this).attr('href').substring(1));
});
In summary, you shouldn't use any kind of delayed methods.
Isn't the problem quite apparent, or am I being silly? In the following function, you handle the clicks on the map, you listen to click, delay them by 500ms and then run through your function.
$("#tab2.tab_content #map").delayed('click', 500, function() {
state = window.location.hash.substring(1);
alert(state);
jsonLink = 'http://ml.uscm.org/ministries.json?state=' + state + '&active=true&callback=?';
getMapResults();
return false;
});
But at the point where you alert your state, it's empty because you haven't yet set it. Your return false; will also stop the browser from changing the hash.
Try this function, and I bet you'll get something:
$("#tab2.tab_content #map").delayed('click', 500, function() {
setTimeout(function(){
var state = window.location.hash.substring(1);
alert(state);
jsonLink = 'http://ml.uscm.org/ministries.json?state=' + state + '&active=true&callback=?';
getMapResults();
}, 500);
});
A quick way to get it working would be to do the following:
$("#tab2.tab_content #map a").delayed('click', 500, function(e) {
state = $(this).attr('href').replace('#', '');
alert(state);
});
you could then easily change the hash manually by also adding this into the callback:
window.location.hash = state;
but your real issue is that your a (anchors) aren't changing the hash themselves, which makes it seem like there is somewhere in your code that's stopping it.
In Chrome, only can set hash will anchor, eg:
<a href="#exemplo" />
If you do this by setting a hash of another element, try to exchange it for an anchor.
in this link you see the chrome accepts the hash property:
http://www.w3schools.com/jsref/prop_loc_hash.asp
How about you modify your code a bit,
$("#tab2.tab_content #map a").click(function(){
console.log($(this).attr("href"));//this outputs the value to the console
});
this will output #CA for California
i.e.
$("#tab2.tab_content #map a").delayed('click', 500, function() {
//state = window.location.hash.substring(1);
state = $(this).attr("href").substring(1);
alert(state);
jsonLink = 'http://ml.uscm.org/ministries.json?state=' + state + '&active=true&callback=?';
getMapResults();
return false;
});
In your code if you place a breakpoint (ln36 state = window.location.hash.substring(1);) when the event is fired, the window has not yet changed location so the hash does not exist at that point.
When I check in Chrome's inspector, it appears that your anchors uses href from a different namespace, which isn't declared in your svg tag.
<a xlink:href="#SD">
Firefox seems fine with that, but Chrome doesn't seems to guess how to interpret this correctly.
From this link, I've found:
Bind the required namespaces
SVG is a namespaced XML dialect, and as a consequence all the XML
dialects used in your SVG documents must be bound to their namespace
as specified in the Namespaces in XML recommendation. It is sensible
to bind the SVG and XLink namespaces at a minimum, and possibly also
the XML Events namespace.
So, try to add xmlns:xlink="http://www.w3.org/1999/xlink" to your SVG tag.
Edit
As I can see in the image you posted, you declared xmlns:xlink well in your .svg. But in the rendered page by Chrome, there is no such thing!
Here's what I see (Chrome 30) :
<svg height="100%" version="1.1" width="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 165 96" preserveAspectRatio="meet" style="overflow: hidden; position: relative;">
From here, it's beyond my knowledge: can some namespace for a tag be stored somewhere else by the browser? I've searched through its DOM properties, can't find it.
Another clue: you declared xmlns:svg too.
Quoted from the former link:
Be careful not to type xmlns:svg instead of just xmlns when you bind
the SVG namespace. This is an easy mistake to make, but one that can
break everything. Instead of making SVG the default namespace, it
binds it to the namespace prefix 'svg', and this is almost certainly
not what you want to do in an SVG file. A standards compliant browser
will then fail to recognise any tags and attributes that don't have an
explicit namespace prefix (probably most if not all of them) and fail
to render your document as SVG.
Additional doc about xlink
I appreciate all the help and suggestions.
The answer to the question ended up that I needed to make the paths for the URLs absolute, not relative.
So as an example, a line in the JavaScript went from:
"AL": {tooltip: 'Alabama', attr: {fill: '#F9B625', href: '#AL'}},
To:
"AL": {tooltip: 'Alabama', attr: {fill: '#F9B625', href: 'http://richcoy.com/locator/index2.html#AL'}},
Once I changed this for all 50 states a click on the map pulled the data from the jasonp feed correctly and displayed it on the page in Chrome, as well as in Firefox.
var myURL = document.URL; //example http://www.ourdomain.com/thispage.html#IL
var getTheMagicWord = myURL.split("#");
console.log(getTheMagicWord[1]); //logs IL

How to update bootstrap popover text?

I am using bootstrap-popover to show a message beside an element.
If I want to show different text in the popover after the first time, the text does not change. Re instantiating the popover with new text does not overwrite.
See this js fiddle for a live example:
http://jsfiddle.net/RFzvp/1/
(The message in the alert and the message in the dom is inconsistent after the first click)
The documentation is a bit light on how to unbind: http://twitter.github.com/bootstrap/javascript.html#popovers
Am I using this wrong? The Any suggestions on how to work around?
Thanks
You can access the options directly using the jquery data closure dictionary like this:
$('a#test').data('bs.popover').options.content = 'new content';
This code should work fine even after first initializing the popover.
Hiya please see working demo here: http://jsfiddle.net/4g3Py/1/
I have made the changes to get your desired outcome. :)
I reckon you already know what you are doing but some example recommendations from my end as follows for sample: http://dl.dropbox.com/u/74874/test_scripts/popover/index.html# - sharing this link to give you idea for different link with different pop-over if you will see the source notice attribute data-content but what you wanted is working by the following changes.
Have a nice one and hope this helps. D'uh don't forget to up vote and accept the answer :)
Jquery Code
var i = 0;
$('a#test').click(function() {
i += 1;
$('a#test').popover({
trigger: 'manual',
placement: 'right',
content: function() {
var message = "Count is" + i;
return message;
}
});
$('a#test').popover("show");
});​
HTML
<a id="test">Click me</a>
​
just in-case anyone's looking for a solution that doesn't involve re-instantiating the popover and just want to change the content html, have a look at this:
$('a#test').data('popover').$tip.find(".popover-content").html("<div>some new content yo</div>")
Update: At some point between this answer being written and Bootstrap 3.2.0 (I suspect at 3.0?) this changed a little, to:
$('a#test').data('bs.popover').tip().find ............
Old question, but since I notice that the no answer provides the correct way and this is a common question, I'd like to update it.
Use the $("a#test").popover("destroy");-method. Fiddle here.
This will destroy the old popover and enable you to connect a new one again the regular way.
Here's an example where you can click a button to set a new popover on an object that already has a popover attached. See fiddle for more detail.
$("button.setNewPopoverContent").on("click", function(e) {
e.preventDefault();
$(".popoverObject").popover("destroy").popover({
title: "New title"
content: "New content"
);
});
The question is more than one year old, but maybe this would be usefull for others.
If the content is only changed while the popover is hidden, the easiest way I've found is using a function and a bit of JS code.
Specifically, my HTML looks like:
<input id="test" data-toggle="popover"
data-placement="bottom" data-trigger="focus" />
<div id="popover-content" style="display: none">
<!-- Hidden div with the popover content -->
<p>This is the popover content</p>
</div>
Please note no data-content is specified. In JS, when the popover is created, a function is used for the content:
$('test').popover({
html: true,
content: function() { return $('#popover-content').html(); }
});
And now you can change anywhere the popover-content div and the popover will be updated the next time is shown:
$('#popover-content').html("<p>New content</p>");
I guess this idea will also work using plain text instead of HTML.
On Boostrap 4 it is just one line:
$("#your-element").attr("data-content", "your new popover content")
You can always directly modify the DOM:
$('a#test').next(".popover").find(".popover-content").html("Content");
For example, if you want a popover that will load some data from an API and display that in the popover's content on hover:
$("#myPopover").popover({
trigger: 'hover'
}).on('shown.bs.popover', function () {
var popover = $(this);
var contentEl = popover.next(".popover").find(".popover-content");
// Show spinner while waiting for data to be fetched
contentEl.html("<i class='fa fa-spinner fa-pulse fa-2x fa-fw'></i>");
var myParameter = popover.data('api-parameter');
$.getJSON("http://ipinfo.io/" + myParameter)
.done(function (data) {
var result = '';
if (data.org) {
result += data.org + '<br>';
}
if (data.city) {
result += data.city + ', ';
}
if (data.region) {
result += data.region + ' ';
}
if (data.country) {
result += data.country;
}
if (result == '') {
result = "No info found.";
}
contentEl.html(result);
}).fail(function (data) {
result = "No info found.";
contentEl.html(result);
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
Hover here for details on IP 151.101.1.69
This assumes that you trust the data supplied by the API. If not, you will need to escape the data returned to mitigate XSS attacks.
Learn't from previous answers
let popOverOptions = {
trigger: 'click',
...
};
// save popOver instance
let popOver = $(`#popover-unique-id`).popover(popOverOptions);
// get its data
let popOverData = popOver.data('bs.popover');
// load data dynamically (may be with AJAX call)
$(`#popover-unique-id`).on('shown.bs.popover', () => {
setTimeout(() => {
// set content, title etc...
popOverData.config.content = 'content/////////';
// updata the popup in realtime or else this will be shown next time opens
popOverData.setContent();
// Can add this if necessary for position correction:
popOver._popper.update();
}, 2000);
});
This way we can update popover content easily.
There's another way using destroy method.
http://jsfiddle.net/bj5ryvop/5/
Bootstrap 5.0 update
let popoverInstance = new bootstrap.Popover($('#element'));
And then:
popoverInstance._config.content = "Hello world";
popoverInstance.setContent();
(Caution: it will update popover content globally, so if you have multiple open popovers then they all will be updated with "Hello world")
I found Bootstrap popover content cannot changed dynamically which introduces the setContent function. My code (hopefully helpful to someone) is therefore:
(Noting that jquery data() isn't so good at setting as it is getting)
// Update basket
current = $('#basketPopover').data('content');
newbasket = current.replace(/\d+/i,parseInt(data));
$('#basketPopover').attr('data-content',newbasket);
$('#basketPopover').setContent();
$('#basketPopover').$tip.addClass(popover.options.placement);
if jQuery > 4.1 use
$("#popoverId").popover("dispose").popover({
title: "Your new title"
content: "Your new content"
);
Bootstrap 5.1
I tried about 8 different ways to change the content for my Bootstrap 5.1 project, but none worked. I could see the values in the underlying popover object and could change them, but they didn't show on the page.
I got it going by first using the Bootstrap Popover's selector option, which the docs don't explain that well, but basically amounts to putting a watch on the page, so if new popover elements are added to the page (with the selector) they will become popovers automatically.
$(function() {
// set up all popovers
new bootstrap.Popover(document.body, {selector: 'has-popover');
})
then in my ajax call where some different content has been fetched, I remove the existing popover div, change the attribute with the text, and add it again:
var $pop = $('#pop_id1234')
var html = $pop[0].outerHTML // save the HTML
$pop.remove()
var $new = $(html).attr('data-bs-content',popoverText) // data('bs-content') becomes bsContent which won't work
$('#pop-container').append($new)

Categories