It seems I can't select DOM elements from a website I've loaded using the inAppBrowser plugin. When I log document.getElementById("input") it's null. The resources I've read on this have treated selecting elements as trivial, but I seem unable.
Here's the code I'm using:
var obj = {
link: "https://www.foolink.com",
input: "barInput",
func: function(obj) {
document.getElementById("input").value = obj.input;
}
}
var ref = cordova.InAppBrowser.open(obj.link, "_blank");
ref.addEventListener('loadstop', function() {
ref.executeScript({code:obj.func(obj)})
})
Has anyone else encountered this before? Using jquery to get selectors on gives me selectors from the index.html file, not the inAppBrowser window.
*edit: currently using inAppBrowser 1.4.0 and cordova 6.0.0
Frix33 got the gears turning with his answer, but I don't think it specifically identifies the problem so posting my own. The script injected into the page must be a STRING or else it is just executed by the app, which is a different document hence the null result before. It works if you replace {code: obj.func(obj)} with:
var codePass = "document.getElementById('input').value = '"+ obj.input +"';"
var ref = cordova.InAppBrowser.open(obj.link, "_blank", "location=yes");
ref.addEventListener('loadstop', function(event) {
ref.executeScript({code:codePass})
});
You can pass as many script lines as needed using that format.
This work for me (cordova 6.1.1, inappbrowser 1.4.0, platform Android):
...
ref.addEventListener('loadstop', function () {
ref.executeScript(
{ code: "document.getElementById('inputID')" },
function (values) {
alert(values[0]);
}
);
...
Related
I m a newbie to programming in JS, i though of giving a try in intel XDk.
I browsed some videos and according to one tutorial, i followed the exact same steps as he did,
But unfortunately, he got the script in emulator working while mine got stuck with a problem of `alert is not defined (W117)' but he didn't got that error,.
My JS code as follows:
/*jshint browser:true */
/*global $ */(function()
{
"use strict";
/*
hook up event handlers
*/
function register_event_handlers()
{
/* button #submit */
$(document).on("click", "#submit", function(evt)
{
/* your code goes here */
var name = document.getElementById('name').value;
var place = document.getElementById('place').value;
var job = document.getElementById('job').value;
var gender = document.getElementById('gender').value;
var reason = document.getElementById('reason').value;
var text = name + place + job + gender + reason ;
alert(text);
return false;
});
}
document.addEventListener("app.Ready", register_event_handlers, false);
})();
Any help is appreciated..
I don't have your full JS code and cannot find an 'app.Ready' event (which is being run on load looks like). To perform check based on jQuery 'ready' event just use below code:
$(document).on("click", "#submit", function(evt) {
var name = document.getElementById('name').value;
var place = document.getElementById('place').value;
var job = document.getElementById('job').value;
var gender = document.getElementById('gender').value;
var reason = document.getElementById('reason').value;
var text = name + place + job + gender + reason;
alert(text);
return false;
});
With the 3900 (and later) releases of the XDK there is a known issue where the alert() (and related) functions no longer work inside the Simulate tab. This was due to an upgrade of the version of Chromium that is built into the node-webkit image that underlies the XDK. At this time there is no workaround, other than to use the Cordova dialogs plugin as an alternative.
Note that in some WebViews (the runtime that your Cordova app runs in when it runs on a real device) the alert() function does not exist, since it is an optional feature and not required. Keep in mind that your Cordova app does not actually run in a browser, it runs in an embedded runtime that feels a bit like a browser, but it's not. Just like Node.js apps have a JavaScript runtime engine, so do WebViews, but neither runtime is hosted within a browser.
In general, using the alert() function is not a good option for a real app.
I open and execute this function inside the opened browser via injected javascript (aka inappbrowser callbacks).
The function works because I see the alerts. The inappbrowser is opened via window.open(...):
var f_el_tname = document.body.getElementsByTagName("the_tag")[0];
//the above alerted "undefined" in android browser and the correct value in the desktop
//rewriting variable for debug purposes
f_el_tname = document.body.getElementsByTagName("the_tag");
alert(f_el_tname.length); //this gives "0" in phonegap android browser and "1" in desktop (correct)
for(var i = 0; i < f_el_tname.size; i++){
alert(f_el_tname); //this does not even run
}
Why exactly is this happening? With "desktop" and "android" I'm referring to accessing the phonegap instance in the desktop or in android, so the code and context are virtually the same. Any idea on why?
EDIT :
I think this might be happening because document in document.body.getElementsByTagName("the_tag"); is referring to the app document and not the document inside the inappbrowser. How can I get the document inside the browser inside the loadstop callback?
The windows is opened by var ref = window.open(...);
EDIT 2: as requested, here is the code
var ref = window.open(url,'_blank','location=yes,toolbar=no,hidden=yes','closebuttoncaption=Return');
ref.addEventListener('loadstop', function(){
var f_el_tname = ref.document.body.getElementById("l_fdb");
//the above gives an error
});
Try to do it using inappbrowser.executeScript:
var ref = cordova.InAppBrowser.open(url,'_blank','location=yes,toolbar=no,hidden=yes');
ref.addEventListener('loadstop', function() {
var code = '(function(){ return document.getElementById("l_fdb"); })()';
ref.executeScript({code: code}, function(results) {
console.log('l_fdb: ' + results);
});
});
Examples of executeScript usage can be found in the plugin tests.
I have developed a simple chat application where I am using the $window.onbeforeunload to notify other users when somebody closes the tab/browser (basically when the user leaves the room).
Here is my code
$scope.onExit = function() {
$scope.chatstatus.$add({
status: $scope.getUsername + ' left'
});
};
$window.onbeforeunload = $scope.onExit;
This is working absolutely fine on desktop browsers but not on the Android Chrome browser. The onbeforeunload function is not getting triggered at all.
Please suggest a solution/workaround. Thanks.
EDIT: As mentioned in the comments that it is a known issue, kindly suggest a workaround if not the solution.
Looks like you need to check for both onbeforeunload and onunload.
This answer looks like a good way to do that.
Android Chrome window.onunload
window.onunload = window.onbeforeunload = function() {
var guid = sessionStorage.getItem("WindowGUID");
var tmp = JSON.parse(localStorage.getItem("WindowGUIDs"));
tmp = tmp.remove(guid); // remove is a custom prototype fn
localStorage.setItem("WindowGUIDs", JSON.stringify(tmp));
});
I posted this question to the PhantomJS mailing list a week ago, but have gotten no response. Hoping for better luck here...
I've been trying to use PhantomJS to scrape information from YouTube, but haven't been able to get it working.
Consider a YouTube video embedded into a web page via an iframe element. If you load the URL referenced by the src attribute directly into a browser, you get a full-page version of the video, where the video is encapsulated in an embed element. The embed element is not present in the initial page content; rather, some script tags on the page cause some Javascript to be evaluated which eventually adds the embed element to the DOM. I want to be able to access this embed element when it appears, but it never appears when I load the page in PhantomJS.
Here's the code I'm using:
var page = require("webpage").create();
page.settings.userAgent = "Mozilla/5.0 (X11; rv:24.0) Gecko/20130909 Firefox/24.0";
page.open("https://www.youtube.com/embed/dQw4w9WgXcQ", function (status) {
if (status !== "success") {
console.log("Failed to load page");
phantom.exit();
} else {
setTimeout(function () {
var size = page.evaluate(function () {
return document.getElementsByTagName("EMBED").length;
});
console.log(size);
phantom.exit();
}, 15000);
}
});
I only ever see "0" printed to the console, no matter how long I set the timeout. If I look for "DIV" elements I get "3", and if I look for "SCRIPT" elements I get "5", so the code seems to be sound. I just never find any "EMBED" tags, even though if I load the URL above in my browser I do find one soon after page-load.
Does anyone have any idea what the problem might be? Thanks in advance for any help.
Patrick's answer got me on the right track, but the full story is as follows.
Youtube's Javascript probes the browser's capabilities before deciding whether to create some kind of video element. After trawling through the minified code, I was eventually able to fool Youtube into thinking PhantomJS supported HTML5 video by wrapping document.createElement in the page's onInitialized callback.
page.onInitialized = function () {
page.evaluate(function () {
var create = document.createElement;
document.createElement = function (tag) {
var elem = create.call(document, tag);
if (tag === "video") {
elem.canPlayType = function () { return "probably" };
}
return elem;
};
});
};
However, this was a misstep; to get the <embed> tag I was originally after, I needed to make Youtube's code think PhantomJS supports Flash, not HTML5 video. That's also doable:
page.onInitialized = function () {
page.evaluate(function () {
window.navigator = {
plugins: { "Shockwave Flash": { description: "Shockwave Flash 11.2 e202" } },
mimeTypes: { "application/x-shockwave-flash": { enabledPlugin: true } }
};
});
};
So that's how it's done.
phantomjs does not support flash, or the html5 video element.
As on option - try to build phantomjs with video/audio support by yourself.
Original answer link: https://github.com/ariya/phantomjs/issues/10839#issuecomment-331457673
I was asked to take a look at what should be a simple problem with one of our web pages for a small dashboard web app. This app just shows some basic state info for underlying backend apps which I work heavily on. The issues is as follows:
On a page where a user can input parameters and request to view a report with the given user input, a button invokes a JS function which opens a new page in the browser to show the rendered report. The code looks like this:
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}
});
The page that is then opened has the following code which is called from Page_Load:
rptViewer.ProcessingMode = ProcessingMode.Remote
rptViewer.AsyncRendering = True
rptViewer.ServerReport.Timeout = CInt(WebConfigurationManager.AppSettings("ReportTimeout")) * 60000
rptViewer.ServerReport.ReportServerUrl = New Uri(My.Settings.ReportURL)
rptViewer.ServerReport.ReportPath = "/" & My.Settings.ReportPath & "/" & Request("Report")
'Set the report to use the credentials from web.config
rptViewer.ServerReport.ReportServerCredentials = New SQLReportCredentials(My.Settings.ReportServerUser, My.Settings.ReportServerPassword, My.Settings.ReportServerDomain)
Dim myCredentials As New Microsoft.Reporting.WebForms.DataSourceCredentials
myCredentials.Name = My.Settings.ReportDataSource
myCredentials.UserId = My.Settings.DatabaseUser
myCredentials.Password = My.Settings.DatabasePassword
rptViewer.ServerReport.SetDataSourceCredentials(New Microsoft.Reporting.WebForms.DataSourceCredentials(0) {myCredentials})
rptViewer.ServerReport.SetParameters(parameters)
rptViewer.ServerReport.Refresh()
I have omitted some code which builds up the parameters for the report, but I doubt any of that is relevant.
The problem is that, when the user clicks the show report button, and this new page opens up, depending on the types of parameters they use the report could take quite some time to render, and in the mean time, the original page becomes completely unresponsive. The moment the report page actually renders, the main page begins functioning again. Where should I start (google keywords, ReportViewer properties, etc) if I want to fix this behavior such that the other page can load asynchronously without affecting the main page?
Edit -
I tried doing the follow, which was in a linked answer in a comment here:
$.ajax({
context: document.body,
async: true, //NOTE THIS
success: function () {
window.open(Address);
}
});
this replaced the window.open call. This seems to work, but when I check out the documentation, trying to understand what this is doing I found this:
The .context property was deprecated in jQuery 1.10 and is only maintained to the extent needed for supporting .live() in the jQuery Migrate plugin. It may be removed without notice in a future version.
I removed the context property entirely and it didnt seem to affect the code at all... Is it ok to use this ajax call in this way to open up the other window, or is there a better approach?
Using a timeout should open the window without blocking your main page
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
setTimeout(function() {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}, 0);
}
});
This is a long shot, but have you tried opening the window with a blank URL first, and subsequently changing the location?
$("#btnShowReport").click(function(){
If (CheckSession()) {
var pop = window.open ('', 'showReport');
pop = window.open ('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>', 'showReport');
}
})
use
`$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.location.href='<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>';
}
});`
it will work.