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)
Related
I have this search function , which should refresh the page first (clean what was in the page)and then show the results.
What happens is that the page shows the results first and then refreshs the page.
searchForm.addEventListener("submit" , function(event)
{
window.location.reload(); //should do this first
event.preventDefault();
searchedName.innerText = searchBar.value;
changeLogoImage(searchedName);
giveCompanieSymbol(searchedName);
TurnVisible(companyLogo);
TurnVisible(overviewDataContainer);
TurnVisible(separadoresAnalise);
TurnVisible(personaliseParagrafo);
}
)
I can't think of a easy/simple solution to do this without creating another function or separated events. Isn't there an easier way to say to this function :
"First reload the page , then show the results." ?
I thought this is what would happen If I place the reload() in the first line of the function but doesn't seems to be the case.
You can't refresh the page and then make modifications to it, because the environment in which your code was running (along with your code) has been torn down and discarded by the process of reloading the page.
Instead, either:
Modify the page in place rather than refreshing it.
or
Encode the search information in query string parameters and assign teh URL to window.location to load the new page, and read and apply those query string parameters on page load.
or
Use sessionStorage to store them temporarily and then, again, apply them on page load.
#1 is a common approach these days. Given it's search information, #1 is also quite a normal way to do this.
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")
I have two jQuery mobile pages (#list and #show). There are several items on the #list page with different IDs. If I click on item no.5, the ID no5 will be stored in localStorage and I will be redirected to page #show
Now the problem:
Storing the ID in localStorage works, but the next page shows me not the item no.5, but it shows me an old item, that was in the localStorage before.
script from page #list
localStorage.setItem("garageID", $(this).attr('id'));
window.location.replace("#show");
I encountered this problem too (and not on a mobile : on Chromium/linux).
As there doesn't seem to be a callback based API, I "fixed" it with a timeout which "prevents" the page to be closed before the setItem action is done :
localStorage.setItem(name, value);
setTimeout(function(){
// change location
}, 50);
A timeout of 0 might be enough but as I didn't find any specification (it's probably in the realm of bugs) and the problem isn't consistently reproduced I didn't take any chance. If you want you might test in a loop :
function setLocalStorageAndLeave(name, value, newLocation){
value = value.toString(); // to prevent infinite loops
localStorage.setItem(name, value);
(function one(){
if (localStorage.getItem(name) === value) {
window.location = newLocation;
} else {
setTimeout(one, 30);
}
})();
}
But I don't see how the fact that localStorage.getItem returns the right value would guarantee it's really written in a permanent way as there's no specification of the interruptable behavior, I don't know if the following part of the spec can be legitimately interpreted as meaning the browser is allowed to forget about dumping on disk when it leaves the page :
This specification does not require that the above methods wait until
the data has been physically written to disk. Only consistency in what
different scripts accessing the same underlying list of key/value
pairs see is required.
In your precise case, a solution might be to simply scroll to the element with that given name to avoid changing page.
Note on the presumed bug :
I didn't find nor fill any bug report as I find it hard to reproduce. In the cases I observed on Chromium/linux it happened with the delete operation.
Disclaimer: This solution isn't official and only tested for demo, not for production.
You can pass data between pages using $.mobile.changePage("target", { data: "anything" });. However, it only works when target is a URL (aka single page model).
Nevertheless, you still can pass data between pages - even if you're using Multi-page model - but you need to retrieve it manually.
When page is changed, it goes through several stages, one of them is pagebeforechange. That event carries two objects event and data. The latter object holds all details related to the page you're moving from and the page you're going to.
Since $.mobile.changePage() would ignore passed parameters on Multi-page model, you need to push your own property into data.options object through $.mobile.changePage("#", { options }) and then retrieve it when pagebeforechange is triggered. This way you won't need localstorage nor will you need callbacks or setTimeout.
Step one:
Pass data upon changing page. Use a unique property in order not to conflict with jQM ones. I have used stuff.
/* jQM <= v1.3.2 */
$.mobile.changePage("#page", { stuff: "id-123" });
/* jQM >= v1.4.0 */
$.mobile.pageContainer.pagecontainer("change", "#page", { stuff: "id-123" });
Step two:
Retrieve data when pagebeforechange is triggered on the page you're moving to, in your case #show.
$(document).on("pagebeforechange", function (event, data) {
/* check if page to be shown is #show */
if (data.toPage[0].id == "show") {
/* retrieve .stuff from data.options object */
var stuff = data.options.stuff;
/* returns id-123 */
console.log(stuff);
}
});
Demo
We have a intermittent bug that it's been hard to track, the bug consists in randomly (so we think) when redeeming a code, the entire code value disappears upon making the order...
Doing our self the same process manually, it does not, never ever, happen!
So I thought recording the user actions, every action:
click links
submit inputs
page views
ended up making up this set of rules, and appending to the end of the master page:
$(function() {
// log this page view
log2Loggly('Page View', '');
// for each click
$("a").click(function() {
var ref = $(this).attr("onclick").length > 0 ? $(this).attr("onclick") : $(this).attr("href");
log2Loggly('Link clicked', ref);
});
// forms
$("form").submit(function() {
var dt = $(this).serialize();
log2Loggly('Form submited', dt);
});
});
and using Loggly I can send each action, as they get the hold of the date and IP, it's easier to match a user IP upon our system.
I keep seeing this services like CrazyEgg that record all user actions, but we can't match the user, it's anonymous data!
What I really liked was to search for IP and get the entire user tree as kind'a of an organigram of what the user did... maybe I'm able to pull this off with the data I have, but I would like to ask 2 things prior to adventure on this idea
Is there any kind of service for this outthere that you might come across before?
what more should I track to make it "almost perfect"?
Very confused here.
I have a search box which reads a list of school names from my database. When I select a school, the id (from the db) gets put in a hidden textbox.
I also have a search box which reads a list of courses from my database. However, I made the query so that it only reads the courses from the selected school.
It does that, in theory.
I was planning to pass the school id, which I grab from the hidden box, to the search script which in turn passes it to my database query. However, the variable I put my school id in doesn't seem to be updating.. yet it does. Let me explain.
I come on the page. The school for my test account has id 1. The id number in my hidden box is indeed 1. I search for a school which I know has some courses assigned to it: the id number in the box changes to 3.
I have a JS variable called school_id which I declared outside of my $(document).ready. I assume that means it's global (that's what I got taught even though SO told me once it isn't really the correct way to do this. Still have to look into that). I wrote a function which updates this variable when the school search box loses focus:
$("#school").blur(function() {
school_id = $("#school_id").val();
});
A quick javascript:alert(school_id); in my browser bar also shows the updated variable: it is now 3 instead of 1.
Onto the search script part of my page (excerpt of the script):
script:"/profiel/search_richting?json=true&limit=6&id=" + school_id + "&"
As you can see, I pass the school_id variable to the script here. However, what seems to be happening is that it always passes '1', the default variable when the page loads. It simply ignores the updated variable. Does this string get parsed when the page loads? In other words, as soon as the page loads, does it actually say &id=1? That's the only idea I can come up with why it would always pass '1'.
Is there a way to make this variable update in my script string? Or what would be the best way to solve this? I'm probably missing out on something very simple here again, as usual. Thanks a lot.
EDIT
Updated per request. I added a function getTheString as was suggest and I use the value of this function to get the URL. Still doesn't work though, it still seems to be concatenating before I get a chance to update the var. HOWEVER, with this code, my ajax log says id:[object HTMLInputElement], instead of id:1. Not sure what that means.
<script type="text/javascript">
var school_id;
$(document).ready(function() {
$("#school").blur(function() {
school_id = $("#school_id").val();
});
// zoekfunctie
var scholen = {
script:"/profiel/search_school?json=true&limit=6&",
varname:"input",
json:true,
shownoresults:false,
maxresults:6,
callback: function (obj) { document.getElementById('school_id').value = obj.id; }
};
var as_json = new bsn.AutoSuggest('school', scholen);
var richtingen = {
script: getTheString(),
varname:"input",
json:true,
shownoresults:true,
maxresults:6
};
var as_json2 = new bsn.AutoSuggest('studierichting', richtingen);
});
function getTheString() {
return "/profiel/search_richting?json=true&limit=6&id=" + school_id + "&";
}
</script>
This is because the URL is static, it is not updated as the ID changes.
You should update the URL as part of the code you wrote to get the ID:
$("#school").blur(function() {
school_id = $("#school_id").val();
// update URL here ...
});
Aren't you concatenating script:"/profiel/search_richting?json=true&limit=6&id=" + school_id + "&" before the event is fired and the var updated?
Okay. So the problem was my third party plug-in instead of the code I wrote. I fixed this by editing the code of the autoSuggest plugin so it now includes my id field in the AJAX request.
var url = this.oP.script+this.oP.varname+"="+encodeURIComponent(this.sInp)+"&id="+ $("#school_id").val();
Thanks to everyone who tried to help me out!