Executing a jquery function stored as a variable name - javascript

I'm struggling with figuring out how to call/execute a function in jQuery. I've done quite a bit of searching and find what looks like it should be the answer, but it doesn't seem to work. I assume it is a scope issue since everything else seems to match examples I've found here, but I'm relatively new to jQuery and can't quite figure it out.
Basically, when the "bookmark" button is clicked, it uses ajax to create an entry in the database, and changes the format of the clicked button. This acts as expected. The trick is this requires someone to be logged in. The actual click of the button adds a #bookmarkme anchor to the url - if they aren't logged in (this is where things start getting tricky for me), the log in window pops up and they are prompted to sign up/log in, and the page reloads to set all the log in variables properly. This also works as expected. Where it breaks down is once the user logs in and the page reloads, I can't get the "bookmarkFunction" to run.
<script type="text/javascript">
var loggedin = <?php echo $loggedin; ?>;
var headerButtonScript = function(){
var bookmarkFunction = $("#bookmark").click(function(){
var directoryName = "<?php echo $directoryName;?>";
if(loggedin == 1 && $("#bookmark").hasClass("headerButton")){
$.ajax({
type: "POST",
url: "../includes/bookmarkProcess.php",
data: {directory: directoryName},
success: function(data, status){
if(data == "success"){
$("#bookmark").switchClass("headerButton", "headerButtonDisabled", 1000, "easeInOutQuart");
$("#bookmark").text("Bookmarked");
}
}
});
}
else{
$("#signInContent").toggleClass('hidden');
$("#signInPopUp").toggleClass('hidden');
}
});
};
var headerButtonsAfterLoad = function(){
var currentAddress = window.location.href;
var hashPosition = currentAddress.indexOf("#");
var targetLocation = currentAddress.substring(hashPosition+1);
if(targetLocation == "bookmarkme"){
if(loggedin==1){
//CALL bookmarkFunction HERE;
//I know I get to this location when expected, because placing an alert("message") gives me the pop up
}
}
};
$(document).ready(headerButtonScript);
$(window).bind('load',"",headerButtonsAfterLoad);
</script>
Based on my research, I have tried the following lines (one line attempted each time rather than all at once, of course) in the excerpt to try to call the function, but no luck yet.
if(targetLocation == "bookmarkme"){
if(loggedin==1){
//CALL bookmarkFunction HERE;
bookmarkFunction();
bookmarkFunction.run();
bookmarkFunction.call();
bookmarkFunction.apply();
}
}
Any help on locating my issue - scope, methods, or otherwise - is greatly appreciated!

"I need the script to take the same action it would when I click on the bookmark button (ID = bookmark) when the page reloads and has the anchor #bookmarkme"
This will do what you want^
$('#bookmarkme').trigger('click');

$("#bookmark").click(). should work.
Remember, calling a jQuery method on a jQuery object returns the original jQuery object. So if you say:
var bookmark=$('#bookmark')
Then bookmark is set to the jQuery object (which contains the element of id=bookmark as a property).
If you attach methods to the object like this:
var bookmark=$('#bookmark').click(function(){console.log('You clicked!')})
Then, yes, the element with id bookmark will now call this event when you click it, but the click method on a jquery object returns the original jquery object. That means bookmark will still be equal to $("#bookmark"), not the function in the click method.
So in conclusion, when you attach an event to a jquery object, like click or hover, it goes into the dom and attaches the event, and then returns the original jquery object. That way you can do things like:
var bookmark=$("#bookmark").click(function(){console.log("you clicked")}).mouseover(function(){console.log("you moused over")})
And you can keep attaching events forever and ever, and bookmark will always be equal to $("#bookmark")

Related

Ajax call in "for" loops skips odd/even iterations

If I am here asking it is because we are stuck on something that we do not know how to solve. I must admit, we already searched in StackOverflow and search engines about a solution.. but we didn't manage to implement it / solve the problem.
I am trying to create a JavaScript function that:
detects in my html page all the occurrences of an html tag: <alias>
replaces its content with the result of an Ajax call (sending the
content of the tag to the Ajax.php page) + localStorage management
at the end unwraps it from <alias> tag and leaves the content returned from ajax call
the only problem is that in both cases it skips some iterations.
We have made some researches and it seems that the "problem" is that Ajax is asynchronous, so it does not wait for the response before going on with the process. We even saw that "async: false" is not a good solution.
I leave the part of my script that is interested with some brief descriptions
// includes an icon in the page to display the correct change
function multilingual(msg,i) {
// code
}
// function to make an ajax call or a "cache call" if value is in localStorage for a variable
function sendRequest(o) {
console.log(o.variab+': running sendRequest function');
// check if value for that variable is stored and if stored for more than 1 hour
if(window.localStorage && window.localStorage.getItem(o.variab) && window.localStorage.getItem(o.variab+'_exp') > +new Date - 60*60*1000) {
console.log(o.variab+': value from localStorage');
// replace <alias> content with cached value
var cached = window.localStorage.getItem(o.variab);
elements[o.counter].innerHTML = cached;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(window.localStorage.getItem(o.variab),o.counter);
} else {
console.log(o.variab+': starting ajax call');
// not stored yet or older than a month
console.log('variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language);
$.ajax({
type: 'POST',
url: my_ajax_url,
data: 'variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language,
success: function(msg){
// ajax call, storing new value and expiration + replace <alias> inner html with new value
window.localStorage.setItem(o.variab, msg);
var content = window.localStorage.getItem(o.variab);
window.localStorage.setItem(o.variab+'_exp', +new Date);
console.log(o.variab+': replacement from ajax call');
elements[o.counter].innerHTML = content;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(msg,o.counter);
},
error: function(msg){
console.warn('an error occured during ajax call');
}
});
}
};
// loop for each <alias> element found
//initial settings
var elements = document.body.getElementsByTagName('alias'),
elem_n = elements.length,
counter = 0;
var i = 0;
for(; i < elem_n;i++) {
var flag = 0;
console.info('var i='+i+' - Now working on '+elements[i].innerHTML);
sendRequest({
variab : elements[i].innerHTML,
api_key : settings.api_key,
language : default_lang,
counter : i
});
$(elements[i]).contents().unwrap().parent();
console.log(elements[i].innerHTML+': wrap removed');
}
I hope that some of you may provide me some valid solutions and/or examples, because we are stuck on this problem :(
From our test, when the value is from cache, the 1st/3rd/5th ... values are replaced correctly
when the value is from ajax the 2nd/4th .. values are replaced
Thanks in advance for your help :)
Your elements array is a live NodeList. When you unwrap things in those <alias> tags, the element disappears from the list. So, you're looking at element 0, and you do the ajax call, and then you get rid of the <alias> tag around the contents. At that instant, element[0] becomes what used to be element[1]. However, your loop increments i, so you skip the new element[0].
There's no reason to use .getElementsByTagName() anyway; you're using jQuery, so use it consistently:
var elements = $("alias");
That'll give you a jQuery object that will (mostly) work like an array, so the rest of your code won't have to change much, if at all.
To solve issues like this in the past, I've done something like the code below, you actually send the target along with the function running the AJAX call, and don't use any global variables because those may change as the for loop runs. Try passing in everything you'll use in the parameters of the function, including the target like I've done:
function loadContent(target, info) {
//ajax call
//on success replace target with new data;
}
$('alias').each(function(){
loadContent($(this), info)
});

jquery ajax call getting old data when re-used

I have an ajax call that builds a small graph in a popup window. The html for the link is re-used in many different links for different devices on the page. What happens, is that when you click a graph for the first device, you get that device. You click a button for the second device, you get that device, however, if you keep clicking away, after the third click or so, you suddenly start getting only the first device, over and over. I think my variables are being cached in some odd way, and I don't understand:
the HTML:
<a class="bluebtn graphbutton ingraph" href="http://wasat/cgi-bin/rrdjson.cgi?res=3600&start=-24h&end=now-1h&uid=28.7B2562040000" data-uid="28.7B2562040000" data-name="Laundry Room Freezer"></a>
<a class="bluebtn graphbutton ingraph" href="http://wasat/cgi-bin/rrdjson.cgi?res=3600&start=-24h&end=now-1h&uid=28.F7A962040000" data-uid="28.F7A962040000" data-name="Garage Temp"></a>
The code in question:
$(document).ready(function() {
$('.graphbutton').click(function(e) {
var formURL = $(this).attr("href");
var uid = $(this).data("uid");
var name = $(this).data("name");
e.preventDefault();
$.ajax({
url: formURL,
dataType: "json",
cache: false,
context: this,
success: function(data){
console.log("calling mkgraph with uid "+uid+" name " +name);
make_graph(data.data, uid, name);
},
error: function(ts) {
console.log(ts.responseText); }
});
}); /* clickfunc */
}); /*docready */
What happens:
Click freezer:
"calling mkgraph with uid 28.7B2562040000 name Laundry Room Freezer"
Click Garage:
"calling mkgraph with uid 28.F7A962040000 name Garage Temp"
Click Garage again:
"calling mkgraph with uid 28.7B2562040000 name Laundry Room Freezer"
Some of these links are being manufactured by the make_graph() function. I'm a bit worried that this is the issue, and somehow the ajax thing needs to be re-initialized after doing this?
By request, the relevant code in make_graph() that I think is causing my issue here. Basically, I'm editing the buttons in the css popup on the fly, and I think this is creating a wierd situation where the ajax binding is bound to the old href, and not being updated, even though the link is correct in the produced html. This is consistent with the effect where the binding only gets mangled on the third attempt.
$(".ingraph").each(function() {
this.href = $(this).attr("href").replace(/uid=.*/g, 'uid=' + uid);
this.setAttribute('data-uid' ,uid);
if (devname.length > 0) {
this.setAttribute('data-name', devname);
}
});
EDIT: adding a long answer:
I have multiple buttons on the main page. Each one specifies a "uid" that gets fed to rrdjson.cgi, which takes the uid and finds the data for that device, and returns it as json. When make_graph() recieves this json data, it populates a css popup, with the graph, and edits 5 buttons so they reference that UID. Those 5 buttons change the timescale of the graph by re-requesting the data from rrdjson.cgi.
What I am worried is happening, is that I click on the frige, it changes the uid's of the buttons inside the popup to reference the frige. Then I close that, click on the garage, it also changes the uid's and correctly shows the garage data. Then I click on one of the buttons inside the popup for the garage, and poof, I get the refrigerator again. I suspect that ajax "remembers" the old values for $(this).attr("href") etc and passes those values to the code, rather than re-reading the contents of the HTML. (perhaps instead of HTML, I meant DOM there, I'm a little vauge on the difference, but I suspect I meant DOM)
Maybe the answer is to somehow un-register the ajax binding to those buttons and re-register it every time make_graph() changes them? How would I do the un-register? .off() ? .unbind() ?
After much gnashing of teeth, and google, I have answered my own question.
https://forum.jquery.com/topic/jquery-data-caching-of-data-attributes
Turns out, jquery caches "data" types, but not attr types. So when I do:
uid = $(this).data("uid");
vs
uid = $(this).attr("data-uid");
I get wildly different results. I guess the moral of the story is that .data is super evil.. :)
If you add a random value to your url like
var formURL = $(this).attr("href")+"?rv="+Math.random();
you'll force the ajax call to reload the URL. You can use the cache property (set it to false) JQuery will load the data again, but any proxy may send a cached version.
(Please check that there are no other attributes set in the url, otherwise set "&rv="+Math.random(); (& instead of ?) use
var formURL = $(this).attr("href");
formURL + (formURL.indexOf("?") > 0 ? "&rv=" : "?rv=" )+ Math.random();
Your problem should not have something to do with make_graph() as uid and name depend on $('.graphbutton')
(if not make_graph(), or some other function, changes the attributes of your buttons)

Javascript How to check if a call is being made, and kill it if it is

Using jQuery I'm writing a website api call in Javascript, which so far works pretty well. When a person updates a number in a text input it does a call to the API and updates a field with the response. It gets problematic however, when I user quickly makes a lot of changes. The javascript then seems to pile up all queries, and somehow does them side by side, which gives the field to be updated kind of a stressy look.
I think one way of giving the user a more relaxed interface, is to only start the API call after the user finished editing the input field for more than half a second ago. I can of course set a timeout, but after the timeout I need to check if there is not already a call under way. If there is, it would need to be stopped/killed/disregarded, and then simply start the new call.
First of all, does this seem like a logical way of doing it? Next, how do I check if a call is underway? And lastly, how do I stop/kill/disregard the call that is busy?
All tips are welcome!
[EDIT]
As requested, here some of the code I already have:
function updateSellAmount() {
$("#sellAmount").addClass('loadgif');
fieldToBeUpdated = 'sellAmount';
var buyAmount = $("#buyAmount").val();
var sellCurrency = $("#sellCurrency").val();
var buyCurrency = $("#buyCurrency").val();
var quoteURL = "/api/getQuote/?sellCurrency="+sellCurrency
+"&buyAmount="+buyAmount
+"&buyCurrency="+buyCurrency;
$.get(quoteURL, function(data, textStatus, jqXHR){
if (textStatus == "success") {
$("#sellAmount").val(data);
$("#sellAmount").removeClass('loadgif');
}
});
if (fieldToBeUpdated == 'sellAmount') {
setTimeout(updatesellAmount, 10000);
}
}
$("#buyAmount").on("change keyup paste", function(){
updateSellAmount();
});
If you make your AJAX call like this:
var myAjaxDeferred = $.ajax("....");
You can check it later with:
if (myAjaxDeferred.state() === "pending") {
// this call is still working...
}

How do I get my jquery post request to work with the variable stored from a function on a click?

I have been banging my head against the wall trying to pass a game's name through to my php function as soon as a user clicks a button. The idea is the user clicks a button, which has a value of its videogame name, then the php script checks that game's ranking and returns that ranking to the html. I have made post requests work before, and even here when I manually set the variable name to one of the Games to test it, it works. Please help!
<script>
$(document).ready(function(){
//global n variable
n = $();
$('#target').click(function(){
//set value of n to the game's name
n = $(this).val();
});
//then send the name as term to my php function to deal with it and return
//the ranking
$.post('getTotal.php', {term: n}, function(data){
//been trying to see if anything comes through for debugging purposes
alert(data);
//commented this out for now, just puts it in the div I left open
//$('#total').html(data);
});
});
</script>
simply when the user clicks the button. inside the click handler, obtain the value and perform an http post
$ajax or $POST
eg -
$(document).ready(function() {
$('#target').click(function()
$.ajax({
type: "POST",
url: "url...",
data: "n="+nVal+",
success: function(html){
alert( "Submitted");
}
});
});
});
You should put the $.post into your click handler... so it will only run when you actually click the button... now your code sets up an n variable, its value is an empty jQuery object (why?). Then it attaches a click handler on the button. Then it runs a $.post request - n is still an empty jQuery object. Clicking the button happens much later...
Also, using globals should be avoided. The var keyword should be used when declaring variables.

My AJAX is only firing once,

I ahave some ajax that is fired when a checkbox is clicked, it essentially sends a query string to a PHP script and then returns the relevant HTML, however, if I select a select it works fine if I then slect another checkbox as well as the previous I get no activity what so ever, not even any errors in firebug, it is very curious, does anyone have any ideas?
//Location AJAX
//var dataObject = new Object();
var selected = new Array();
//alert(selected);
$('#areas input.radio').change(function(){ // will trigger when the checked status changes
var checked = $(this).attr("checked"); // will return "checked" or false I think.
// Do whatever request you like with the checked status
if(checked == true) {
//selected.join('&');
selected = $('input:checked').map(function() {
return $(this).attr('name')+"="+$(this).val();
}).get();
getQuery = selected.join('&')+"&location_submit=Next";
alert(getQuery);
$.ajax({
type:"POST",
url:"/search/location",
data: getQuery,
success:function(data){
//alert(getQuery);
//console.log(data);
$('body.secEmp').html(data);
}
});
} else {
//do something to remove the content here
alert($(this).attr('name'));
}
});
I see you are using the variable checked = $(this).attr("checked"); I think this might be a problem because checked is a standard JS attribute native to JS. You can compare checked normally on an element and see if it is true or false. I would start by changing the name of your variable and move on from there.
The other thing that could be happening is you might be losing your listener which might be caused by your variable selected. You do not need to declare selected outside your listener. Just declare it inside when you set it.
And if THAT doesn't help, providing some markup would help debug this issue because it seems like there is a lot going on here.
Good luck.
I turned out that because my ajax loads in a new page on success the actions were not being put on the elements as they were only being loaded once on DOM ready, I moved the all the script into a function and call that on DOM Ready now and it works great.

Categories