javascript property race condition - javascript

I have a phonegap project on iPhone and Android. The issue appears to be a race condition on the surface, but I don't understand how it happens. Users are able to click on a button which has a closure callback that sets a property of an object, and then clears the screen and loads the main menu. In code:
button.onclick = function (employee) {
return function () {
employee.task = "some task";
returnToMenu();
}
}(employees[i]);
After the user is back on the main menu, they can click on a button that loads a screen which displays all the users. If an employee has that task property set, additionally formatting should be done to the button for that employee.
if (employee.task)
// style the button being created for this employee
Somehow, if one clicks fast enough, the formatting is not done. If you click back (to the main menu), and reload the screen, the formatting is now done. Given the code above, I do not see how employee.task could possibly return undefined after the menu has been loaded. What's going on here?

Related

Content hide/show

my goal is to hide the content of my homepage when someone visits. onClick to begin button the content should be shown. Content should stay open when user goes to other page and comes back to homepage. But it will be hidden when user closes the window and opens up the homepage again. To achieve this goal I have put the following code but it keeps the content open even when user closes and opens the window. So please help me out.
if (! localStorage.noFirstVisit) {
// hide the element
$("#content").hide();
// check this flag for escaping this if block next time
localStorage.noFirstVisit = "1";
}
Another issue is when the content shows the design gets little messed up(by widening the divs, bringing horizontal scroll)
$(".roll-button").click(function(){
$("#content").show();
});
I would highly appreciate if you check website, suggest me fix or show me proper way to achieve this goal. url:iamicongroup.com
You can totally use sessionStorage to detect whether it is new tab(window) or not.
When you first visit this page, set sessionStorage.noFirstVisit = "1";.
After you go to another page and back, sessionStorage.noFirstVisit is still "1".
But when you close the tab or browser and open the page newly again, sessionStorage.noFirstVisit will be undefined.
Documentation is here
The documentation also provide the difference between sessionStorage and localStorage.
I would suggest reading this: Detect Close windows event by Jquery
It goes over window unloading (beforeunload), which I believe is what you're after. You can set/unset your localstorage values there based on certain criteria being met; for example:
$(window).on("beforeunload", function() {
if(localStorage.noFirstVisit = "1" {
// do something
localStorage.noFirstVisit = "[someValue]"
}
else {
// do something
localStorage.noFirstVisit = "1"
}
})
Another issue is when the content shows the design gets little messed up(by widening the divs, bringing horizontal scroll)
how about adding something like 'ng-cloak' in angular, to avoid the undesirable flicker effect caused by show/hide.
when clicking the roll-button, it prevents the divs from showing unfinished..

How can I reuse a cloned element?

I have a Bootstrap modal on my page. Basically, what happens is the user picks some options on the page, clicks a go button and that modal pops up and gets populated with the live output of the job they started.
After the job runs, I'd like for the user to be able to close the modal, choose more options, and run the job again. The problem is, I can't seem to get rid of the output from the previous job.
I tried this answer, which was to clone the div and use replaceWith() to restore the content to it's original state. This works for the first two times (job runs once, then when you start another the modal is back to it's original state), but for any time after that, the modal pops up with the content of the previous run until it's text gets overridden.
I have this at the beginning, to capture the contents before anything is done:
$(document).ready(function() {
modalHold = $("#postModal").clone();
});
And, this runs when the modal closes:
$('#postModal').on('hidden.bs.modal', function (){
$("#postModal").replaceWith(modalHold.clone());
})
I would've expected the replaceWith(modalHold.clone()) to replace it with a new clone of the original element, however it seems that I'm still modifying the original. Any help would be appreciated, or if there's a better way of doing this I'd be glad to hear it.
Bootstrap does some javascript magic with the Modal, so I guess you can't just clone whole the Modal's HTML. As a workaround you may try to play with class="modal-body" node only, clone and replace it.
But the truth is on another way. You need to implement a function which would reset your inputs and call it each time the Modal is being hidden.
var modalDefault = {
input1: '',
input2: 'Hello!'
};
var resetModal = function() {
$('#modalInput1').val(modalDefault.input1);
$('#modalInput2').val(modalDefault.input2);
}
// ...
$('#postModal').on('hidden.bs.modal', resetModal);
Not sure why I didn't think of this to begin with, but dhilt's answer helped point me in the right direction. The idea of creating defaults and just switching back to those could be helpful in some cases, but I had some content (including job info and a loading bar) inside the modal that I'd really like to be displayed each time a job starts, until it is done and the output can be displayed.
Instead of doing any fancy cloning, I placed that content into a div and just grabbed its innerHTML:
$(document).ready(function() {
modalHold = $('#jobOutputHolder').html();
});
When the .load () runs, it will update #jobOutputHolder with the output of the job. Then, on hide of the modal:
$('#postModal').on('hidden.bs.modal', function (){
$('#jobOutputHolder').html(modalHold);
})
With this method, I can run a job, see the loading screen, see the job output, close the modal, and repeat as many times as I need without ever seeing the output of previous jobs.

Stop Safari extension from caching messages

I'm having problems with creating a safari extension that has been causing me headaches.
The problem is this: I have created an extension that gets images from a web page using an injected script. I have a function in the popover that displays the web images and allows the user to click and send the selected image to a backend. This all goes through the global page which handles signals and messages. The scenario is this:
When the popover opens, it sends a signal to the global page to initiate the response (image URLs) from the injected script.
When the global page gets the message from the injected script, it calls the function in the popover passing in the data from the injected script as an argument.
The popover shows all images returned from the global page via the injected script.
The problem is that every time I open the popover, it appends the images from the last call instead of giving a fresh list of images. For instance, on first popover open, I get one image (assuming the page has only one image). If I close the popover and open it again, I get two of the same image. If I close and open the popover a third time, it appends the first image with the one from the second time and gives me 3 of the same image. On the fourth open of the popover I get 1 + 1 + 1 + 1, so 4 images. So it seems to be appending the messages and not giving me a fresh message every time.
My question is: how can I destroy the messages that are being cached after each popover closes? I hope I am being clear. Perhaps something else is happening with my code that I am not aware of. Please help if you can. Here is my code from the global HTML:
function popoverHandler(event) {
//check for popover opening
if (event.target.identifier === "MyPopUp") {
//send message to injected script to send page info
safari.application.activeBrowserWindow.activeTab.page.dispatchMessage("getContent", '', false);
//this works fine, I get this message every time popover opens
console.log('getContent message sent');
//listen for message containing page info from injected script
safari.application.addEventListener('message', function (messageEvent) {
//only get message from current tab
if (messageEvent.name === "pageInfo" && messageEvent.message.url === safari.application.activeBrowserWindow.activeTab.url) {
pageInfo = messageEvent.message;
//the problem seems to be in here. Every time I open the popover, //I get the current page info plus all the page info messages from //the previous time I open the pover, all duplicates of the previous //messges
console.log(pageInfo);
// call a function in the popover, passing the pageInfo data //received from the injected script
safari.extension.popovers[0].contentWindow.onPageDetailsReceived(pageInfo);
}
});
}
}
Ok, so I was able to solve the problem. First of all, I separated the popoverHandler from the eventListener. For some reason, it was firing the function too many times and returning several lists of the same images. The major issue, however, was that in the popover.js, I was storing the list of images as a var. When I removed the var, the data stopped persisting and I was getting a fresh list every time.

Browser 'back' button that steps back to second stage of Javascript?

I have a problem brought about by a specific client requirement in nopCommerce.
I have a page - lets say page1 - which shows a block image which you then have to click through to get to the main part of the page (no matter how much I try to dissuade them from the extra click they are adamant - basically it's a 'glamour shot' before going to the main product grid/category page).
I have this JavaScript for the page load:
switch(window.location.pathname) {
case "/store/page1":
$(".category-page").hide();
break;
etc. (there are other functions for other things)
Followed by:
$(".landing_click").click(function () {
$(".landing_page").hide();
$(".category-page").show();
});
This all works great and displays the product grid (category page) as it should after clicking through the main image. However after viewing an individual product from the grid (going through to product details) clicking the back button on the browser takes you back to the first stage of the page1, so you have to click through the splash image/glamour shot again to get to the product grid.
To me this is logical and it is working as it should, but I need to find a way so that when the user is clicking the back button out of a product, it goes back to the product grid. Like this:
Is this possible with JavaScript? It needs to use the browser back button rather than a specific other button, although I could add one of those in addition as well.
If it were a straightforward website it would be relatively easy, but I am confined by the limitations of nopCommerce and the way the Category pages function, hence why I am looking for a JavaScript answer if possible so I can simply adapt what I already have.
Thanks
I would use location.hash to do it like this:
switch(window.location.pathname) {
case "/store/page1":
if(window.location.hash == "#landing") {
$(".landing_page").show();
$(".category-page").hide();
}
else {
$(".landing_page").hide();
$(".category-page").show();
}
break;
//The rest here
}
Followed by:
$(".landing_click").click(function () {
window.location.hash = "#category";
$(".landing_page").hide();
$(".category-page").show();
});
Now when you are in the product details page, a click on the back button will move you to /store/page1#category loading the category page directly.

Run Code After Function is Finished OR DIV Appears

I have written a Userscript for Facebook and it groups similar notifications together. Now, using just a static HTML page with old notifications I had, the script works 100%.
Here's the problem: the DIV that holds notifications by default, has no notifications in it until the user clicks on the Notification button. Facebook has an inline onclick event that displays the DIV (Notifications menu) and uses AJAX to grab the notifications. Since my userscript only runs on startup, it finds nothing there - it has no effect on the page. I tried using a .click() event but right when you click the Notifications button it runs my code. The thing is, Facebook is still running it's AJAX request for the notifications, meaning that there are still no notifications for my script to work with, making it have no effect.
I don't want to use a generic setTimeout because I don't want the user to have to see the notifications before and then suddenly see them after. Is there a way to monitor the DIV so once the notifications are added, it runs? Or that once Facebook finishes it's AJAX request, it will run my code?
You can setInterval() to monitor the div's innerHTML, once populated you can run.
Here's the problem: the DIV that holds notifications by default, has no notifications in it until the user clicks on the Notification button. Facebook has an inline onclick event that displays the DIV (Notifications menu) and uses AJAX to grab the notifications.
...
I don't want to use a generic setTimeout because I don't want the user to have to see the notifications before and then suddenly see them after. Is there a way to monitor the DIV so once the notifications are added, it runs?
Yes there is:
var notificationDiv = document.getElementById(...);
var lastTimeoutID = null;
var main = function(evt){
// evt.target is the inserted element
// if you expect more elements, then do the following:
lastTimeoutID = setTimeout(function(){
lastTimeoutID = null;
// uncomment below block if you only need to do the work once.
/*
notificationDiv.removeEventListener("DOMNodeInserted", main, false);
*/
// do your work here.
}, 500); // waiting 500ms for next element to be added, otherwise doing work.
if (lastTimeoutID) {
clearTimeout(lastTimeoutID);
lastTimeoutID = null;
}
};
notificationDiv.addEventListener("DOMNodeInserted", main, false);
All of the timeout code above might be removable depending on what it is you're userscript is doing.
Maybe you can add a setTimeout loop. Something like
setTimeout(function(){
/* check for divs */
if(/* divs are found */){
//apply code
}
else {
setTimeout(/* loop again */);
}
},1000);

Categories

Resources