Update instance in the first method before continue to run the second method in the same command - windows-phone-7

I have a method like this
public void LoadProgrammeListFromChannel(TVDailyScheduleParam scheduleParam, Action callback)
{
string url = Helper.GetProgrammeUrl(scheduleParam.Day, scheduleParam.Channel.Id); //1//
WebClient client = new WebClient(); //2//
client.OpenReadCompleted += new OpenReadCompletedEventHandler((sender, e) => //3//
{//5//
if (e.Error != null)
return;
try
{
_programmeList.Clear();
_programmeList = DataService.GetProgrammeList(e.Result);
// call method in MainVM to update View
callback();
}
finally
{
// close file stream
e.Result.Close();
}
});
client.OpenReadAsync(new Uri(url, UriKind.Absolute)); //4//
}
and I have a cammand like this
LoadWhatsonProgrammeCommand = new RelayCommand(()=>
{
foreach (TVDailyScheduleParam param in _tvDailyScheduleVM.ChannelList.Select(c => new TVDailyScheduleParam(DateTime.Today, c, false)))
{
TVDailyScheduleParam param2 = param;
_tvDailyScheduleVM.LoadProgrammeListFromChannel(param2, ()=>
{
RaisePropertyChanged(TV_DAILY_SCHEDULE_VM);
});
_tvDailyScheduleVM.GetWhatsonProgramme(param2, ()=>
{
RaisePropertyChanged(TV_DAILY_SCHEDULE_VM);
});
}
});
Now when I invoke the command. At first it runs _tvDailyScheduleVM.LoadProgrammeListFromChannel and invoke the LoadProgrammeListFromChannel method.
In the LoadProgrammeListFromChannel method it runs from 1 -> 2 -> 3. At 3, it's not completed sothat it runs to 4 and then back to the command and continue to run _tvDailyScheduleVM.GetWhatsonProgramme.
But the _programmeList in LoadProgrammeListFromChannel is not updated so that GetWhatsonProgramme does not run exactly.
How can I go back to LoadProgrammeListFromChannel in order to run 3 to update _programmeList before running _tvDailyScheduleVM.GetWhatsonProgramme ?

The behaviour you describe is "by design". Your method LoadProgrammeListFromChannel makes an asynchroneous call. This means within your method the sequence is 1 -> 2 -> 3 -> 4 -> return -> execute code in calling function -> then sometime later 5 and then the callback.
As a result LoadProgrammeListFromChannel and GetWhatsonProgramme are executed in parallel. So if GetWhatsonProgramme needs always to run after LoadProgrammeListFromChannel you will have the call to move GetWhatsonProgramme into your callback method, i.e.
LoadWhatsonProgrammeCommand = new RelayCommand(()=> {
var channelList = _tvDailyScheduleVM
.ChannelList
.Select(c => new TVDailyScheduleParam(
DateTime.Today,
c,
false
));
foreach (TVDailyScheduleParam param in channelList) {
TVDailyScheduleParam param2 = param;
_tvDailyScheduleVM.LoadProgrammeListFromChannel(param2, ()=> {
RaisePropertyChanged(TV_DAILY_SCHEDULE_VM);
_tvDailyScheduleVM.GetWhatsonProgramme(param2, ()=> {
RaisePropertyChanged(TV_DAILY_SCHEDULE_VM);
});
});
}
});
Alternatively, you could subscribe to the PropertyChangedEvent of your ViewModel and if the TV_DAILY_SCHEDULE_VM property has been changed, call the GetWhatsonProgramme from there, although this might not be desireable.

Related

RxJs channing, setting and reading external values

I'm new in rxjs world and I have to rewrite some code. So, I draft my ideas.
I have a request, which could fail and return an observable. I simulate that with the ob-variable and two map operations. Then, I try to catch an error. I need the result in my local variable selected and raise an event on isChanged. I call my function now via subscription. I don't need a result.
My question: Is one big pipe enough and can I use following approach for the work with my local variables?
import { of, map, Observable, tap, Subject, throwError, EMPTY } from 'rxjs';
import { catchError } from 'rxjs/operators';
let selected = 0;
const isChanged = new Subject<number>();
function myfunc(): Observable<boolean> {
const ob = of(1,3,4,5,7);
return ob.pipe(
// simulates a http request
map(v => v*2),
// simulates a rare error condition
map(v => {
// if (v === 8) { throw `four`; }
if (v === 10) { throw `ten`; }
return v;
}),
// play with different failure situations
catchError((e) => {
if (e === `four`) {
return of(4);
}
if (e === `ten`) {
return EMPTY;
}
console.warn(e);
return throwError(e);
}
),
// I need the result in a local variable
// I need a information about success
// I need the result not really
map((res) => {
selected = res;
isChanged.next(res);
return true;
})
);
}
console.log(`a: selected is ${selected}`);
isChanged.subscribe(v =>
console.log(`b: isChanged received: ${v}, selected is ${selected}`));
console.log(`c: selected is ${selected}`);
// I have to call the function
myfunc().subscribe((b) => {
console.log(`d: selected is ${selected}`);
});
I create the world in Stackblitz too:
https://stackblitz.com/edit/rxjs-6fgggh?devtoolsheight=66&file=index.ts
I see results like expected. But I'm not sure if all ideas are the right way to solve all problems.
Thanks for you thought.

CompletableFuture in case of if statment

I have 2 CompletableFutures and 3 methods that have to occur each after the other.
However, in some cases the second method isn't necessary.
CompletableFuture<Boolean> cf1 = supplyASync.(() ->( doSomething1()));
CompletableFuture<Boolean> cf2 = new CompletableFuture<Boolean>();
if(someThing){
cf2 = cf1.thenApplyAsync(previousResult -> doSomething2());
}
else{
cf2 = cf1;
}
if (SomeThing2) {
cf2.thenApplyAsync(previousResult ->doSomeThing3());
}
Bassicly what I'm trying to do is that doSomething2 will run after doSomething1 (if needed), but anyway that doSomeThing3 will execute after the first or both of them.
Is it the right way to do it ? Or is there better way ?
The code is being executed in sequence, that is first completable future 1, then completable future 2 (if applies) and finally task 3.
By this reason, you can use a single CompletableFuture:
CompletableFuture<Boolean> cf = CompletableFuture.supplyAsync(() -> {
if (doSomething1()) {
doSomething2();
}
doSomething3();
// return something
});
And handling the boolean results would be something like:
CompletableFuture<Boolean> cf = CompletableFuture.supplyAsync(() -> {
boolean result;
if (result = doSomething1()) {
result = doSomething2();
}
return result && doSomething3();
});
// handle future as you need, e.g. cf.get() to wait the future to end (after task 3)

Does Jasmine have an after-advice spy?

When spying on a method, we can either callThrough (use original implementation) or callFake (use a custom implementation).
What I want is a behaviour similar to callThrough but inspect/modify its return value before returning it to the caller.
So I can do something like this:
spyOn(foo, "fetch").and.afterCall(function(result) {
expect(result).toBeDefined();
result.bar = "baz";
return result;
});
Right now the simplest way is doing something like this:
var original = foo.fetch;
foo.fetch = function() {
var result = original.apply(this, arguments);
expect(result).toBeDefined();
result.bar = "baz";
return result;
}
Which is somewhat annoying because now I have to manually restore the spy instead of having the framework automatically does it for me.
Does Jasmine have an after-advice spy?
Generally: no.
You could extend the SpyStrategy object with such a function though:
this.callThroughAndModify = function(resultModifier) {
var result;
plan = function() {
result = originalFn.apply(this, arguments);
return resultModifier(result);
};
return getSpy();
};
You've to clone the above SpyStrategy file and insert that method.
Usage:
var obj = {
fn: function(a) { return a * 2; }
};
spyOn(obj, "fn").and.callThroughAndModify(function(result) {
console.log("Original result: ", result);
return 1;
});
expect(obj.fn(2)).toBe(1);
Drawbacks:
You've to replace the whole SpyStrategy.js
You've to load that script before Jasmine initializes the original SpyStrategy at boot

Nothing happens with my event listener on click in javascript

I have these functions :
createTreeItem: function (num, val)
{
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var i = document.createElementNS(XUL_NS, "treeitem");
var r = document.createElementNS(XUL_NS, "treerow");
var c1 = document.createElementNS(XUL_NS, 'treecell');
var c2 = document.createElementNS(XUL_NS, 'treecell');
var c3 = document.createElementNS(XUL_NS, 'treecell');
i.setAttribute("container", true);
i.setAttribute("open", true);
c1.setAttribute("label", num);
c2.setAttribute("label", val);
c3.setAttribute("value", false);
r.appendChild(c1);
r.appendChild(c2);
r.appendChild(c3);
i.appendChild(r);
i.addEventListener("click", test, false);
return i;
}
test: function ()
{
alert("zero");
}
func: function (liste)
{
try
{
root = document.getElementById("treeRoot");
var current;
for(o in liste)
{
current = createTreeItem(liste[o].id, liste[o].nom_scenario);
root.appendChild(current);
}
}
catch(e)
{
alert(e);
}
}
I am creating elements in a tree and I would like to add event listeners on each element created. The problem is that nothing happens.
In the code, Liste is the response of a json request. It contains all the elements I want to create in my xul file.
I'm not super familiar with this syntax, but my bet is that the test function isn't being 'hoisted' because of how it's being defined. try moving the 'test' function above the 'createTreeItem' function or just defining test like so:
function test() {
...
}
That way when it gets evaluated it will be 'hoisted' to the top so that when you try to add it as the action for the click event, it'll be defined. Not 100% sure this is correct but if I had to bet...

Tracking with Java Script if Ajax request is going on in a webpage or Intercept XMLHttpRequest through Selenium Web driver

I am using Selenium WebDriver for crawling a web site(only for example, I will be crawling other web sites too!) which has infinite scroll.
Problem statement:
Scroll down the infinite scroll page till the content stops loading using Selenium web driver.
My Approach:
Currently I am doing this-
Step 1: Scroll to the page bottom
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("javascript:window.onload=toBottom();"+
"function toBottom(){" +
"window.scrollTo(0,Math.max(document.documentElement.scrollHeight," +
"document.body.scrollHeight,document.documentElement.clientHeight));" +
"}");
Then I wait for some time to let the Ajax Request complete like this-
Step 2: Explicitly wait for Ajax request to be over
Thread.sleep(1000);
Then I give another java script to check if the page is scrollable
Step 3:Check if the page is scrollable
//Alternative to document.height is to be used which is document.body.clientHeight
//refer to https://developer.mozilla.org/en-US/docs/DOM/document.height
if((Long)js.executeScript("return " +
"(document.body.clientHeight-(window.pageYOffset + window.innerHeight))")>0)
If the above condition is true then I repeat the from Step 1 - 3, till condition in Step 3 is false.
The Problem:
I do not want to give the Thread.sleep(1000); in step 2, rather I would like to check using Java Script if the background Ajax request is over and then scroll down further if the condition in Step 3 is true .
PS: I am not the developer of the page so I do not have access to the code running the page, I can just inject java scripts(as in Step 1 and 3) in the web page. And, I have to write a generic logic for any web site with Ajax requests during infinite scroll.
I will be grateful to some one could spare some time here!
EDIT : Ok, after struggling for 2 days, I have figured out that the pages which I am crawling through the Selenium WebDriver can have any of these JavaScript libraries and I will have to pool according to the different Library, for example, In case of the web application using jQuery api, I may be waiting for
(Long)((JavascriptExecutor)driver).executeScript("return jQuery.active")
to return a zero.
Likewise if the web application is using the Prototype JavaScript library I will have to wait for
(Long)((JavascriptExecutor)driver).executeScript("return Ajax.activeRequestCount")
to return a zero.
Now, the problem is how do I write a generic code which could handle most the JavaScript libraries available?
Problem I am facing in implementing this-
1. How do I find which JavaScript Library is being used in the Web Application(using Selenium WebDriver in Java), such that I can then write the corresponding wait methods?
Currently, I am using this
Code
2. This way I will have to write as many as 77 methods for separate JavaScript library so, I need a better way to handle this scenario as well.
In short, I need to figure out if the browser is making any call(Ajax or simple) with or without any JavaScript library through Selenium Web Driver's java implementation
PS: there are Add ons for Chorme's JavaScript Lib detector and Firefox's JavaScript Library detector which detect the JavaScript library being used.
For web pages with Ajax Response during the infinite scroll and using jQuery API(or other actions), before starting to opening the web page.
//Inject the pooling status variable
js.executeScript("window.status = 'fail';");
//Attach the Ajax call back method
js.executeScript( "$(document).ajaxComplete(function() {" +
"status = 'success';});");
Step 1: will remain the same as in the original question
Step 2 Pooling the following script(This is the one which removes the need of Thread.Sleep() and makes the logic more dynamic)
String aStatus = (String)js.executeScript("return status;");
if(aStatus!=null && aStatus.equalsIgnoreCase("success")){
js.executeScript("status = 'fail';");
break poolingLoop;
}
Step 3: No need now!
Conclusion: No need to give blunt Thread.sleep(); again and again while using Selenium WebDriver!!
This approach works good only if there's jQuery api being used in the web application.
EDIT:
As per the the link given by #jayati i injected the javascript-
Javascript one:
//XMLHttpRequest instrumentation/wrapping
var startTracing = function (onnew) {
var OldXHR = window.XMLHttpRequest;
// create a wrapper object that has the same interfaces as a regular XMLHttpRequest object
// see http://www.xulplanet.com/references/objref/XMLHttpRequest.html for reference on XHR object
var NewXHR = function() {
var self = this;
var actualXHR = new OldXHR();
// private callbacks (for UI):
// onopen, onsend, onsetrequestheader, onupdate, ...
this.requestHeaders = "";
this.requestBody = "";
// emulate methods from regular XMLHttpRequest object
this.open = function(a, b, c, d, e) {
self.openMethod = a.toUpperCase();
self.openURL = b;
ajaxRequestStarted = 'open';
if (self.onopen != null && typeof(self.onopen) == "function") {
self.onopen(a,b,c,d,e); }
return actualXHR.open(a,b,c,d,e);
}
this.send = function(a) {
ajaxRequestStarted = 'send';
if (self.onsend != null && typeof(this.onsend) == "function") {
self.onsend(a); }
self.requestBody += a;
return actualXHR.send(a);
}
this.setRequestHeader = function(a, b) {
if (self.onsetrequestheader != null && typeof(self.onsetrequestheader) == "function") { self.onsetrequestheader(a, b); }
self.requestHeaders += a + ":" + b + "\r\n";
return actualXHR.setRequestHeader(a, b);
}
this.getRequestHeader = function() {
return actualXHR.getRequestHeader();
}
this.getResponseHeader = function(a) { return actualXHR.getResponseHeader(a); }
this.getAllResponseHeaders = function() { return actualXHR.getAllResponseHeaders(); }
this.abort = function() { return actualXHR.abort(); }
this.addEventListener = function(a, b, c) { return actualXHR.addEventListener(a, b, c); }
this.dispatchEvent = function(e) { return actualXHR.dispatchEvent(e); }
this.openRequest = function(a, b, c, d, e) { return actualXHR.openRequest(a, b, c, d, e); }
this.overrideMimeType = function(e) { return actualXHR.overrideMimeType(e); }
this.removeEventListener = function(a, b, c) { return actualXHR.removeEventListener(a, b, c); }
// copy the values from actualXHR back onto self
function copyState() {
// copy properties back from the actual XHR to the wrapper
try {
self.readyState = actualXHR.readyState;
} catch (e) {}
try {
self.status = actualXHR.status;
} catch (e) {}
try {
self.responseText = actualXHR.responseText;
} catch (e) {}
try {
self.statusText = actualXHR.statusText;
} catch (e) {}
try {
self.responseXML = actualXHR.responseXML;
} catch (e) {}
}
// emulate callbacks from regular XMLHttpRequest object
actualXHR.onreadystatechange = function() {
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
// onreadystatechange callback
if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") { return self.onreadystatechange(); }
}
actualXHR.onerror = function(e) {
ajaxRequestComplete = 'err';
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
if (self.onerror != null && typeof(self.onerror) == "function") {
return self.onerror(e);
} else if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") {
return self.onreadystatechange();
}
}
actualXHR.onload = function(e) {
ajaxRequestComplete = 'loaded';
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
if (self.onload != null && typeof(self.onload) == "function") {
return self.onload(e);
} else if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") {
return self.onreadystatechange();
}
}
actualXHR.onprogress = function(e) {
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
if (self.onprogress != null && typeof(self.onprogress) == "function") {
return self.onprogress(e);
} else if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") {
return self.onreadystatechange();
}
}
if (onnew && typeof(onnew) == "function") { onnew(this); }
}
window.XMLHttpRequest = NewXHR;
}
window.ajaxRequestComplete = 'no';//Make as a global javascript variable
window.ajaxRequestStarted = 'no';
startTracing();
Or Javascript Two:
var startTracing = function (onnew) {
window.ajaxRequestComplete = 'no';//Make as a global javascript variable
window.ajaxRequestStarted = 'no';
XMLHttpRequest.prototype.uniqueID = function() {
if (!this.uniqueIDMemo) {
this.uniqueIDMemo = Math.floor(Math.random() * 1000);
}
return this.uniqueIDMemo;
}
XMLHttpRequest.prototype.oldOpen = XMLHttpRequest.prototype.open;
var newOpen = function(method, url, async, user, password) {
ajaxRequestStarted = 'open';
/*alert(ajaxRequestStarted);*/
this.oldOpen(method, url, async, user, password);
}
XMLHttpRequest.prototype.open = newOpen;
XMLHttpRequest.prototype.oldSend = XMLHttpRequest.prototype.send;
var newSend = function(a) {
var xhr = this;
var onload = function() {
ajaxRequestComplete = 'loaded';
/*alert(ajaxRequestComplete);*/
};
var onerror = function( ) {
ajaxRequestComplete = 'Err';
/*alert(ajaxRequestComplete);*/
};
xhr.addEventListener("load", onload, false);
xhr.addEventListener("error", onerror, false);
xhr.oldSend(a);
}
XMLHttpRequest.prototype.send = newSend;
}
startTracing();
And checking the status of the status vars ajaxRequestStarted, ajaxRequestComplete in the java code, one can determine if the ajax was started or completed.
Now I have a way to wait till an Ajax is complete, I can also find if the Ajax was triggered on some action
Approach 1:
Your approach is good, just a few changes would do the trick:
Step 1: Improve this step to call the toBottom function at regular interval using window.setInterval. At (c >= totalcount) call window.clearInterval
Setp 2: Instead of checking the page is yet scrollable, check if (c >= totalcount). And this condition every 200ms until (c >= totalcount) returns true.
FYI: If the Step 1 doesn't work in all the browsers then probably, you can refer to line 5210 of Tata-Nano-Reviews-925076578.js and call this with cvariable checking.
Approach 2:
Go to jQuery API and type "ajax". You can find some callback handlers which could be used for ajax requests.
Probably, set a variable before the request is been sent and after it is been received appropriately.
And in between use your original method of scrolling to bottom at regular interval, unless you can no more scroll. At this point clear the interval variable.
Now, regularly check if that interval variable is null or not. Null would mean that you have reached the bottom.
We had to solve the same problem, and managed using a long Javascript function. Just need to add checks to see which library is not undefined.
PS Thanks for giving me an easy answer for how to check for in progress Prototype requests!
eg. Handle JQuery and XHR/Prototype
var jsExecutor = /*Get your WebDriverInstance*/ as IJavaScriptExecutor;
while(/*your required timeout here*/)
{
var ajaxComplete =
jsExecutor.ExecuteScript("return ((typeof Ajax === 'undefined') ||
Ajax.activeRequestCount == 0) && ((typeof jQuery === 'undefined') || $.active == 0)");
if (ajaxIsComplete)
return
}

Resources