Titanium - Webview is not rendered when is loaded by async callback - asynchronous

I have loop that for each item that call a async request to server, create a view with a webview for later add in a scrollview after calc the positions. In the callback, I get the server data and give to webview.
When the load method takes a little longer to perform (In a slow connection, for example), the webview is not rendered.
This happens many times in the device, but few times in the simulator. But, to simulate easily, just put a breakpoint in the load method, delaying the execution.
I suspect that there is a problem when rendering an already added webview.
I simplified the code in a one block for better understanding:
function createView(){
var view = Ti.UI.createView({
//...
});
var webview = Ti.UI.createWebView({});
view.add(webview);
//Callback to process webview content after receive the server data
view.load = function(serverData){
webview.setUrl(serverData.url);
webview.addEventListener('beforeload', function(){
webview.evalJS("var value="+serverData.value+";");
});
};
return view;
};
var views = new Array();
for(i=0;i < data.length;i++){
views[i] = createView();
//Async request to server
var req = Ti.Network.createHTTPClient();
req.onload = function(){
result = JSON.parse(this.responseText);
views[i].load(result);
}
req.open("POST", "http://myserver.com.br/myservice");
req.send({myParam: data[i].value});
}
var scrollView = Ti.UI.createScrollView({
//...
});
for(i=0;i < views.length;i++){
//Calc the positions, not relevant
views[i].width = calculedValue;
views[i].height = calculedValue;
scrollView.add(views[i]);
}
win.add(scrollView);
Im using Titanium SDK 1.8.2 and running on iPad 2 with iOS 5.0.1.

I solved the problem evaluating the javascript data on the callback instead of on event listener
view.load = function(serverData){
webview.setUrl(serverData.url);
//Not on event 'beforeload'
//webview.addEventListener('beforeload', function(){ not on
webview.evalJS("var value="+serverData.value+";");
//});
};
I think that this is related with the UI thread is not called sometimes on event listener

Related

Sign in API end point wont get invoked unless you clear the browsers cache and then reload the page

I have made a website using asp.net and I have set up a sign-in feature that uses OpenID specifically Steam. I have a web API that gets called and that procs the challenge for the open id. When the user clicks sign in it opens a new tab and browser and direct them to sign in api point. On my local pc, it works perfectly however on a hosted app service on Azure it does not. When the window opens it does not call the API. The only way to call the API is to clear the cache (Shift + Ctrl + R). This then reloades the page and the API get called and it works perfect. If I dont clear the cache its just a blank page.
Here is the code for the API
[HttpPost("api/signin"), HttpGet("api/signin")]
public async Task<IActionResult> SignIn(string type)
{
string provider = type;
// Note: the "provider" parameter corresponds to the external
// authentication provider choosen by the user agent.
if (string.IsNullOrWhiteSpace(provider))
{
return BadRequest();
}
if (!await HttpContext.IsProviderSupportedAsync(provider))
{
return BadRequest();
}
// Instruct the middleware corresponding to the requested external identity
// provider to redirect the user agent to its own authorization endpoint.
// Note: the authenticationScheme parameter must match the value configured in Startup.cs
return Challenge(new AuthenticationProperties { RedirectUri = "api/saveuser" }, provider);
}
Here is the code for the function that opens the new window and points to the API when a button is pressed.
handleLoginSteam = () => {
let winHeight = window.screen.height / 1.5;
let winWidth = window.screen.width / 3;
const win = window.open(
'/api/signin?type=Steam',
'Discord Sign In', "height=" + winHeight + ",width=" + winWidth + ",top=" + ((window.screen.height - winHeight) / 2) + ",left=" + ((window.screen.width - winWidth) / 2));
win.opener.location.reload();
const timer = setInterval(() => {
if (win.closed) {
clearInterval(timer);
this.fetchUserData();
}
}, 500);
}
This is a picture of the new window not calling the api
At this point pressing ctrl shift r is the only way to invoke the steam sign in.
I tried adding a random parameter to the link that gets passed to the window to stop caching but it doesnt work!
If any one can help me out I would be greatly apreciated im quite new to asp.netS.
Went through the code seems you are trying to achieve opens the new window and points to the Signin API when a button is pressed and RefreshParentWindow task. Now, based on your code let’s take a look at your code line-by-line.
This is the code to open a popup window.
const win = window.open(
'/api/signin?type=Steam',
'Discord Sign In', "height=" + winHeight + ",width=" + winWidth + ",top=" + ((window.screen.height - winHeight) / 2) + ",left=" + ((window.screen.width - winWidth) / 2));
On the same page(I assume) you have
win.opener.location.reload(); //this will refresh the parent window
const timer = setInterval(() => {
if (win.closed) {
clearInterval(timer);
this.fetchUserData();
}
}, 500);
}
setInterval() It repeats the statements in the specified intervals REPEATEDLY. Now, you are checking if the window is still opened or not using this line of code.
if (win.closed)
this check every second even if the window is closed!
Reference: https://www.w3schools.com/jsref/prop_win_closed.asp
Now follow these steps:
Open child window using the script on your parent page(you already have it there).
Get rid of the code that checks if the window is closed or not. You don't need it, in any way.
When you are done with adding a new record from you child window call these statements.
opener.location.reload(); //This will refresh parent window.
window.close(); //Close child window. You may also use self.close();
The above two lines will be written on the child page. Maybe on buttons click.
<input type="button" onclick="Signin()" value="Signin" />
function AddRecord(){
//Add newrecord.
opener.location.reload(); //This will refresh parent window.
window.close(); //Close child window. You may also use self.close();
}
Reference : https://www.codeproject.com/Questions/1097734/How-to-reload-refresh-the-parent-window-after-chil

Xamarin Offline Sync issue with getting data

I am getting some issues returning data from azure mobile backend api using android emulator. The mobile app is written with Xamarin and I am using MobileServiceClient and IMobileServiceSyncTable. The following is what I have coded:
var _mobileServiceClient = new MobileServiceClient(url);
var store = new MobileServiceSQLiteStore("notesdb.db");
store.DefineTable<Notes>();
_mobileServiceClient.SyncContext.InitializeAsync(store);
var _notesTable = _mobileServiceClient.GetSyncTable<Notes>();
var temp = await _notesTable.ReadAsync();
Backend code is as followed:
public IQueryable<Notes> GetAllNotes()
{
return Query();
}
Whenever I do that, the app will become unresponsive and never returned. Its like it is in deadlock mode.
Has anyone had this problem?
After looking at the MobileServiceClient usage: https://learn.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-dotnet-how-to-use-client-library
Your calls seem fine except one:
_mobileServiceClient.SyncContext.InitializeAsync(store);
Since you are not awaiting this method, the sync context will not be initialized for your next methods.
So just await the method and you should be fine:
await _mobileServiceClient.SyncContext.InitializeAsync(store);
One general rule your can apply almost everytime: always await the methods returning Task objects.
Also since you are in the service/repository layer, you should ConfigureAwait(false) your methods:
var _mobileServiceClient = new MobileServiceClient(url);
var store = new MobileServiceSQLiteStore("notesdb.db");
store.DefineTable<Notes>();
await _mobileServiceClient.SyncContext.InitializeAsync(store).ConfigureAwait(false);
var _notesTable = _mobileServiceClient.GetSyncTable<Notes>();
var temp = await _notesTable.ReadAsync().ConfigureAwait(false);
Doing that your code won't run in the UI thread (well it's not guaranteed but I don't want to confuse you :). Since you are not running the code on the same thread, it will also reduce possible deadlocks.
more on that: https://medium.com/bynder-tech/c-why-you-should-use-configureawait-false-in-your-library-code-d7837dce3d7f

Activity Indicator is not visible on xaml page in xamarin.forms?

I have an activity indicator on xaml page. Initially its IsVisible property is false. I have a button on page. When user click on button it calls a web service to get data. I change the value of IsVisible property to true before calling the service so that activity indicator starts to display on page and after successful calling of service I change its value to again false so that it doesn't show any more on page.
But it is not working. I know the actual problem. When we call the web service the UI thread gets block and it doesn't show the activity indicator.
How I can enable the UI thread when web service gets called so that activity indicator can show on page until we get the data?
Try making your webservice call into an async and await it.
Depending on how you've structured things you may have to use a TaskCompletionSource as the following example demonstrates.
In this example when the button is clicked, the button is made invisible, and the ActivityIndicator is set to IsRunning=True to show it.
It then executes your long running task / webservice in the function ExecuteSomeLongTask using a TaskCompletionSource.
The reason for this is that in our button click code, we have the final lines:-
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
That stop the ActivityIndicator from running and showing, and also set the button back to a visible state.
If we did not use a TaskCompletionSource these lines would execute immediately after calling the ExecuteSomeLongTask if it was a normal async method / function, and would result in the ActivityIndicator not running and the button still being visible.
Example:-
Grid objGrid = new Grid()
{
};
ActivityIndicator objActivityIndicator1 = new ActivityIndicator();
objGrid.Children.Add(objActivityIndicator1);
Button objButton1 = new Button();
objButton1.Text = "Execute webservice call.";
objButton1.Clicked += (async (o2, e2) =>
{
objButton1.IsVisible = false;
objActivityIndicator1.IsRunning = true;
//
bool blnResult = await ExecuteSomeLongTask();
//
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
});
objGrid.Children.Add(objButton1);
return objGrid;
Supporting function:-
private Task<bool> ExecuteSomeLongTask()
{
TaskCompletionSource<bool> objTaskCompletionSource1 = new TaskCompletionSource<bool>();
//
Xamarin.Forms.Device.StartTimer(new TimeSpan(0, 0, 5), new Func<bool>(() =>
{
objTaskCompletionSource1.SetResult(true);
//
return false;
}));
//
return objTaskCompletionSource1.Task;
}
You need to do your work in an asynchronous way. Or in other words: Use Asnyc & Await to ensure, that you UI works well during the call.
You can find more informations in the Xamarin Docs.
async and await are new C# language features that work in conjunction
with the Task Parallel Library to make it easy to write threaded code
to perform long-running tasks without blocking the main thread of your
application.
If you need further asistance, please update your question and post your code or what you have tried so far.

Sending POST variables to a browser window from AIR application

I'm building an AIR application. Basically, what I'm looking to do is using navigateToUrl() to open a browser window, assign it a "name" and then, send variables to that newly opened window using the POST method.
EDIT : I need the window to be visible, this is why I absolutely need to use the navigateToUrl() function
I already know that I CAN'T DO something like this, that the AIR application will send the variables using the GET method...
var vars:URLVariables = new URLVariables();
vars.myVar = "Hello my friend";
var req:URLRequest = new URLRequest("http://example.com/my-page.php");
req.method = "POST":
req.data = vars;
navigateToURL(req);
Considering the amount of variables I have to send (multiline texts) I absolutely need to send my variables using the POST method else Internet Explorer is truncating the query string... Works fine in Firefox and Safari but unfortunately, we will always have (hope not!) to deal with IE..
So I was thinking something like this :
import flash.net.navigateToURL;
private var _timer:Timer;
protected function loadPage():void
{
var req:URLRequest = new URLRequest("http://example.com/my-page.php");
navigateToURL(req, "myPageName");
_timer = new Timer(3000, 1);
_timer.addEventListener(TimerEvent.TIMER, postVars);
_timer.start();
}
protected function postVars(event:TimerEvent):void
{
// I'm looking to send variables using the POST method to "myPageName"
// and possibly using URLVariables()??
_timer.stop();
}
Any idea Flex coders? THANKS!
I think what you're going to need to do is open up a page you have control over, then use ExternalInterface to inject the values into a hidden form and then execute the post operation in that page form.submit(), etc.
This can happen almost instantly and it will all appear very seamless to the end user.

FileReference.download() not working

I'm building a Flex app which requires me to download files.
I have the following code:
public function execute(event:CairngormEvent) : void
{
var evt:StemDownloadEvent = event as StemDownloadEvent;
var req:URLRequest = new URLRequest(evt.data.file_path);
var localRef:FileReference = new FileReference();
localRef.addEventListener(Event.OPEN, _open);
localRef.addEventListener(ProgressEvent.PROGRESS, _progress);
localRef.addEventListener(Event.COMPLETE, _complete);
localRef.addEventListener(Event.CANCEL, _cancel);
localRef.addEventListener(Event.SELECT, _select);
localRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityError);
localRef.addEventListener(IOErrorEvent.IO_ERROR, _ioError);
try {
localRef.download(req);
} catch (e:Error) {
SoundRoom.logger.log(e);
}
}
As you can see, I hooked up every possible event listener as well.
When this executes, I get the browse window, and am able to select a location, and click save. After that, nothing happens.
I have each event handler hooked up to my logger, and not a single one is being called! Is there something missing here?
The problem seems to be with my command being destroyed before this could finish.
For a proof of concept, I set my localRef variable to be static instead of an instance variable, and everything went through successfully! I guess Cairngorm commands kill themselves asap!

Resources