Currently I am attempting to click a dialog box that appears before a page loads. I am using the browser.get(extentionHere) function to load the page in a manner resembling this:
it(..., function(){
browser.get('#/frontPage);
element(dialogIdentifier).click();
When the page loads Protractor does nothing until a timeout, an investigation into this behavior led me to find that it was the result of the page hanging as the rest of the page 'waited' for the dialog to be clicked. In essence the URL was meaningless as Protractor thinks the page has not loaded and treats the dialog as more of a browser feature (it is not) instead of the webpage. Hence, the element(...).click() did not execute, and of course, the program could not continue.
In attempting to find a solution I found the function browser.executeAsyncScript which I thought might allow me to execute multiple functions in an order. My, albeit ignorant, attempt led me to this:
browser.executeAsyncScript('browser.get("#/frontPage")').then(function () {
element(dialogIdentifier)).click();
});
which, as implied by my asking this question, did not work (giving me some sort of "browser is not a function" error), if I am even using this function correctly for the correct purpose it would seem to fit the bill; allowing me to click the dialog.
Any help would be appreciated (and I am not limiting answers to any function. So please, let me know what ideas you have).
Thanks in advance.
I'm assuming that angular isn't loading since the dialog pops up before the page loads. The below code tells protractor not to wait for angular to synchronize and then resume synchronization after the dialog box is clicked.
browser.ignoreSynchronization = true;
browser.get("http://www.google.ca").then(function () {
element(dialogIdentifier).click();
});
browser.ignoreSynchronization = false;
Related
Background: I'm modifying a SharePoint list web part using JSLink. I'm also adding jQuery and jQuery-UI to make the list items display as the jQuery Accordion. It works well, except that I also need to implement the ajax automatic refresh on the web part to refresh the content every 60 seconds.
Problem: When the web part refreshes, the jquery code reverts - the items no longer show in accordion mode. I can open the browser console and type the jquery code manually, e.g., $(".selector").accordion(); and it works fine. This makes me think that I need to find a way to call the jquery code after each web part automatic refresh completes.
Question: So, is there a javascript event or way to find out when an automatic refresh triggers on my webpart so that I can call again my jquery accordion after? Is there something else I could be missing?
Thanks for your time!
The answer was to use this code:
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(MyFunction);
function MyFunction() {
//do something here;
}
Credit to #Thriggle
References:
https://msdn.microsoft.com/en-us/library/bb311028.aspx
https://www.daniweb.com/programming/web-development/threads/247263/ajax-postback-after-endrequest
I believe you can insert your own code or function calls into the callback chain by overriding the _onFormSubmit method of the current instance of the Sys.WebForms.PageRequestManager object.
Sys.WebForms.PageRequestManager.getInstance()._onFormSubmit = function(i){
Sys.WebForms.PageRequestManager.prototype._onFormSubmit.call(this,i);
alert("Refreshing the data..."); // -- your code or function call here
};
When I ran the above code in the F12 console on a page with a list view that had a 25-second refresh, I started seeing the "Refreshing the data..." pop-up every 25-seconds, but I haven't tested it with anything more complicated than that.
I don't know if this is the effects of an update panel or what, but I basically have a drop down list that allows a user to select an item as a filter. When the item is selected it should bring back only one item into a grid view. That is this specific filter will at most bring back the record you are looking for. This works fine if the user clicks an "apply" link to apply the filter. Behind the apply link is some server-side code (C# within an ASP.NET Web Forms application).
We had a request by a user with something to the effect of:
"Why do I have to click the apply button if I make a selection in this
one drop down filter...it should simply get that one record I am
searching for. This helps me because I don't have to click the
"Apply" button."
I agreed with him and thought what is the easiest way to do this...I thought: Simple, I will have an on change event handler of the drop down such that when a selection is made I'll trigger a click event. Something to this effect:
$("#MainContent_ddlCompany").on("change", function() {
var companyId = $("#MainContent_ddlCompany").val();
$("#MainContent_hdnCompanyValue").val(companyId);
$("#<%=ddlCompany.ClientID %>").trigger("chosen:updated");
if (companyId.length > 0) {
$(".apply").click();
$(".apply").removeClass("applyButton");
$(".apply").addClass("resetButton");
} else {
//cleared selection of a company
$(".apply").removeClass("resetButton");
$(".apply").addClass("applyButton");
}
});
At first this didn't work, and I couldn't tell why, but then after some serious googling I changed this line:
$(".apply").click();
To this:
$('.apply')[0].click();
That worked great...so I decided to test it some more. As I kept selecting one filter value after another I noticed the page started to slow down. In fact by the 6th or 7th time it was pretty unusable. I don't know why it's happening, but I suspect again it has to do with the fact that this linkbutton with the class name .apply is inside an update panel.
But still I thought to myself, it was inside of an update panel before I changed my jQuery code to simulate the click event. So why does the page slow down and drag with this little piece of code? Is calling the event from jQuery code rendering something else in the HTML that could be causing this?
If I change my code back and force the user to click the apply button then we are back to a good normal speed. Why is it if I tell jQuery to simulate clicking the button my page slow down? It's doing the same thing, the simulation of the click of this link button is calling its server-side code method whether the user clicks it or I have jQuery click it.
For now I'm at a loss as to why this is happening because this button is in an update panel in either case, yet when I have jQuery click it via $('.apply')[0].click(); the page slows down after several attempts. Yet when I have the user simply click this button (without the jQuery click event) then it works fine?
What am I missing here?
Ugh, well, I found my issue. Because I was using updatepanels I had to wrap my jQuery code to include an add_endRequest. That is, you have something to the effect of:
$(document).ready(function() {
//Some initial event/triggers
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {
//Copy of some initial event/triggers
});
});
Why do I use the endRequest you ask? Well, because updatepanels basically throw away all your events after an asynchronous postback because the HTML at that point (after an update) is rendered again and at that point all events associated with any control inside an update panel are wiped away. At this point of course document.ready() does not run, so I have to resubscribe to these events inside of endRequest. Enter my issue...
I had a huge brain fart where I basically took everything, literally everything inside document ready and copied it into endRequest. In fact, if I remember correctly, I read articles which stated
Whatever you have in document ready simply copy paste into endRequest
That's fine, but you have to be careful here. I was throwing in events that were not wrapped around inside of an updatepanel into endRequest. The result is disastrous...at least for me.
These events would be attached then multiple times..or based on the number of asynchronous postbacks made. In my case, as I was testing I mentioned after the 6th or 7th time performance starts degrading. Well, by that time my controls were being attached that many times to events. For instance, my .apply button along with my dropdownlist were both outside of my updatepanel. But my jQuery code was attaching the change event of my dropdownlist in both document ready and endRequest.
The result is initially it's pretty fast, because it's only in document ready. But as I make asynchronous postbacks these events are being attached every time. For n tests I would have n attached events...in my case the test of 7 yields 7 on change event handlers!
Case in point, do not place any event handlers such as jQuery's on() event for any controls that are NOT inside an update panel. Otherwise you will run into what I ran into which was poor performance as events are happening.
First of all, apologies if this question was answered before.
I'm writing a code in JS to read an Excel File, get the value of the first cell in the column, search for it (it's an ISBN code, which I'm searching with the Google Books API) and get other relevant info, made available through the search (like Title, Subtitle and Author), then proceed to the next line and repeat the process.
My problem is writing the new data back in the Excel File. The code is writing all info in the last used row in the file. While using window.alert to flag the code, I noticed that when the alert was in a for loop, right before the search was initiated, the new data was inserted just fine, but if I tried to use a pause (like a timer function or a while loop to consume time) it didn't help at all.
What I want to know is why that behavior might be happening and, if possible, of course, a possible solution for my problem, since having to use alert as a pause isn't exactly the most interesting solution.
Thanks in advance
Alert will always stop all execution of code, except for web workers. Therefore, If you need to continue execution, use a web worker. Have a look at this for reference (the note part covers this topic partially)
When browsers show a native modal interaction widget, such as an alert, it transitions into a state that waits for the response. In this state, it is allowed to redraw the page and process certain low level events. Here's the code from Mozilla Firefox that alert() and confirm() use:
http://mxr.mozilla.org/mozilla-central/source/toolkit/components/prompts/src/nsPrompter.js#434
This openRemotePrompt function doesn't return until the user clicks "OK" on the alert. However browser behaves differently while the alert is open. A loop repeatedly calls thread.processNextEvent to do certain kinds of work until the dialog is closed. (It doesn't run the application's JavaScript code, since that's meant to be single-threaded.)
When you use a pure JavaScript busy wait, for example, by looping until a certain wall time, the browser doesn't take these measures to keep things moving. Most noticeably, the UI won't redraw while the JavaScript code is looping.
Since some time last year, YouTube made it so that every page is not actually loading an entirely new page, but primarily just re-loading the contents in div#content. You can notice this when you click on a link in YouTube and see the red loading bar at the top of the page.
I have a Greasemonkey script that modified elements on YouTube, but now that YouTube doesn't reload the entire page, the Greasemonkey script no longer fires on every "new" page. How can I make the Greasemonkey script fire on every "new" page that I load on YouTube?
I'm using jQuery in this Greasemonkey script. I tried using functions like .on() with DOMNodeInserted but I can't find the right combination to make it work properly. With the event listeners that I've been using, I end up running my script hundreds of times for each page load, such as with the following:
$('div#page').on('DOMNodeInserted', 'div#content', function() { });
Another solution I was thinking of was making all links on YouTube load pages like normal, without the new way that they are doing it.
I figured it out myself after some research. First off, I don't like solutions that use setTimeout. This is often one method suggested in favor over the deprecated DOMNodeInserted for instance (which I use in some of my scripts, but try to avoid as much as possible), but if possible, I always prefer a solution where the script actually executes after a specific event. I've posted the solution I initially used in the first section below, then the final solution I used in the second section. All code below requires jQuery.
Decent solution, but not the best
At first, I had a solution where I added a click event to all A elements, which would run a timer that ran my script after 2 seconds. This isn't elegant, because if the page loads quickly, then there's a split second where the script hasn't run. And if the page loads for more than two seconds, then the script doesn't run at all. Script below:
$('a').click(function()
{
setTimeout(youtubeFunction, 2000);
});
Much better solution
So I began looking for a solution that was related to what I wanted to accomplish. I eventually found other people with a similar problem to mine (such as people wanting to create a Chrome script that modifies YouTube pages). This led me to this particular Stack Overflow solution, which basically says that the red loading bar at the top of YouTube pages was a CSS transition element, and that it created a transitionend (case sensitive) event when it was finished. The code in the linked solution wasn't complete (for me anyway), but it did explain how to achieve a working solution. The code I have runs only once per page, which is perfect. So here's what I have now:
function youtubePageChange()
{
youtubeFunction();
$('body').on('transitionend', function(event)
{
if (event.target.id != 'progress') return false;
youtubeFunction();
});
}
$(youtubePageChange);
To explain the code above, basically I run the code once for when you first load a YouTube page (such as by typing the URL in the address bar). Then for every subsequent click that requires the progress bar, the code runs again.
Red progress bar code
Oh, and for future reference, when the red progress bar appears at the top of YouTube pages, the site temporarily adds a new DIV to the end of BODY, with the following code:
<div id="progress" class="waiting" style="transition-duration: 400ms; width: 99%;"><dt></dt><dd></dd></div>
You can set a listener which gets called when the page has finished loading.
This is for the new YouTube material design:
body.addEventListener("yt-navigate-finish", function() {
//your code
});
And this for the old:
window.addEventListener("spfdone", function() {
//your code
});
(if you are using *monkey, you'll need to use unsafeWindow)
Keep in mind that the old design will be discontinued, so your script may not work after that.
Hooking into the popstate might be an option, but i was unable to make that work correctly for some reason (youtube may be preventing it from propagating), so i came up with this that shows the concept:
var currentState = "";
setInterval(function(){
if (currentState != history.state["spf-referer"]) {
currentState = history.state["spf-referer"];
console.log("Do Stuff!");
}
},250)
Just watches for the history.state to change, at which point it will log. The state should change any time the url changes, even if it wasn't due to a page reload.
I am implementing a shopping cart for my website, using a pseudo-AJAX Lightbox-esque effect. (It doesn't actually call the server between requests -- everything is just Prototype magic to update the displayed values.)
There is also semi-graceful fallback behavior for users without Javascript: if they click add to cart they get taken to an (offsite, less-desirable-interaction) cart.
However, a user with Javascript enabled who loads the page and then immediately hits add to cart gets whisked away from the page, too. I'd like to have the Javascript just delay them for a while, then execute the show cart behavior once it is ready. In the alternative, just totally ignoring clicks before the Javascript is ready is probably viable too.
Any suggestions?
I now do this with jQuery b/c I vaguely recall browser differences which jQuery takes care of:
Try
$(document).ready(function() {
// put all your jQuery goodness in here.
});
Is your code really that slow that this is an issue? I'd be willing to bet that no one is going to be buying your product that soon after loading the page. In any reasonable case, the user will wait for the page to load before interacting with it, especially for something like a purchase.
But to answer your original question, you can disable the links in normal code, then reenable them using a document.observe("dom:loaded", function() { ... }) call.
You can try, hiding the links in css then show them when the page loads.
<script type="text/javascript">
document.write('<link rel="stylesheet" type="text/css" href="someCssThatHidesLinks.css" />');
window.onLoad = function() {
//show links
}
</script>
This way, if your user doesn't have javascript, then their links are still active, otherwise if they do, then the links are hidden until you load and activate them. Never done this before, but i think this should work if you want to retain the features of your failsafe page.
However, a user with Javascript enabled who loads the page and then immediately hits add to cart gets whisked away from the page, too.
When are you starting up your scripts? If you're using document onload, it will be waiting for all the images to download before initialising, which would indeed give the user a chance to click-to-buy.
If you trigger the JS enhancement when the DOM is ready, either by just putting your <script> at the bottom of the page, or by using a DOMContentLoaded-style event supplied by your framework, the links should adapt fast enough that the user is very unlikely to be clicking the button first.
If you really, really want to delay clicks that are placed between the element first being parsed, and the document being loaded, you could write something like:
<script>
function methodcall(obj, name) {
return function() {
obj[name].call(obj);
};
}
</script>
...
Buy
...
So that it'd just spin there polling (and, on IE, leaking memory) until the link's real click handler was in place. It's pretty ugly though, and fragile in that if your script breaks for some reason (and it's JavaScript, so it's pretty likely that at some point, on some browser, it will), your button will break. This problem applies to all potential solutions that rely on a later-running JavaScript enabling previously-disabled actions.
And there's nothing worse for business than a broken buy button.