Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript executing backwards

An app is using Cordova with InAppBrowser plugin version 3.2.1 to load a webpage built in Asp.Net 4.5.2. We have been experiencing erratic behaviour, so I've made a page to catch the problem and share it here.

This page contains a really simple button executing JS within the onclick event:

<button onclick="alert('1'); alert('2'); alert('3');"> EXECUTION</button>

It works perfectly, but when the website is embed in the app, the execution order runs backwards, displaying:

  • Alert 3
  • Alert 2
  • Alert 1

Using unobstrusive JS with the same results:

<button id="testButton">Test</button>
$(document).ready(function () {
    $("#testButton").click(function () {
       alert('1');
       alert('2');
       alert('3');
    });
});

Running the website in ios with Safari works perfectly fine.

Any idea?

Update

As suggested by @Bergi in the comments, adding a sleep timeout verifies a problem managing synchronous calls. Following code triggers the alerts in the right order:

$("#testButton").click(function () {
    alert('1');
    setTimeout(function () { alert('2'); }, 2000);
    setTimeout(function(){ alert('3'); }, 4000);
});

But not when the timeouts are closer. The following displays the alerts in wrong order:

$("#testButton").click(function () {
    alert('1');
    setTimeout(function () { alert('2'); }, 1);
    setTimeout(function(){ alert('3'); }, 2);
});

Update 2

As proposed by @Bergi in the comments, I've tried:

$("#testButton").click(function () {
    var x = []; x.push(1); x.push(2); alert(x);
});

With a correct result, displaying an alert containing: "1,2".

Issue has been reported.

like image 564
Mario Levrero Avatar asked Jul 07 '20 10:07

Mario Levrero


1 Answers

As @Bergi suggests in a comment, the version of alert() you're calling is likely to be asynchronous on some platforms and synchronous on others. This would explain the behavior you're seeing.

Instead of using window.alert() at all, when you need an alert box you should probably use navigator.notification.alert() from cordova-plugin-dialogs.

Note the signature for this function:

navigator.notification.alert( message, alertCallback, [title], [buttonName] )

The alertCallback function gets called after the alert box is dismissed. Even if some implementations are synchronous (because they use the native browser alert() function) and some are asynchronous, navigator.notification.alert() provides a compatible interface for both cases.

Well, mostly compatible. On platforms where navigator.notification.alert() calls the native alert(), the function will not return until the alert box is dismissed by the user. On platforms that use some other implementation, the function may return immediately. But in both cases, alertCallback will be called when the alert box is dismissed.

cordova-plugin-dialogs also provides similar implementations of navigator.notification.confirm() and navigator.notification.prompt(), each with completion callbacks.

There is an interesting bit of code in tests.js from cordova-plugin-inappbrowser:

window.alert = window.alert || navigator.notification.alert;
if (isWindows && navigator && navigator.notification && navigator.notification.alert) {
    // window.alert is defined but not functional on UWP
    window.alert = navigator.notification.alert;
}

Note how this function sets window.alert to be the same as navigator.notification.alert on platforms where there is no window.alert, and also on UWP. While not directly related to your situation, this illustrates how there may be different implementations on different platforms. But using navigator.notification.alert() should let you write compatible code for all. Just don't assume anything about whether this function returns immediately or waits for the alert to be dismissed - use the alertCallback instead.

like image 168
Michael Geary Avatar answered Oct 23 '22 20:10

Michael Geary