how to delete an element in xamarin forms webview - android

i want to delete an element in Xamarin.forms WebView when it's loading but it return null and app crash . how can i do this?
i tried to check if an element exist but dont have any success.
this is my code
protected void OnNavigating(object sender, WebNavigatingEventArgs args)
{
Webview.Eval("const elements = document.getElementsByClassName(\"footer-section\"); while (elements.length > 0) elements[0].remove();");
}
please help me. thanks

You are getting a null exception because the WebView is not loaded when you try to execute Javascript.
In order to prevent this, you can subscribe to OnNavigated Event:
WebView.Navigated Event
Event that is raised after navigation completes.
So, here is a sample:
public YourWebViewPage()
{
InitializeComponent ();
Webview.Navigated += WebViewNavigated;
}
private void WebViewNavigated(object sender, WebNavigatedEventArgs e)
{
Webview.Eval("const elements = document.getElementsByClassName(\"footer-section\"); while (elements.length > 0) elements[0].remove();");
}

You can try to override function onPageCommitVisible
The Android documentation says:
This callback can be used to determine the point at which it is safe
to make a recycled WebView visible, ensuring that no stale content is
shown. It is called at the earliest point at which it can be
guaranteed that WebView#onDraw will no longer draw any content from
previous navigations. The next draw will display either the
WebView#setBackgroundColor of the WebView, or some of the contents of
the newly loaded page.
This method is called when the body of the HTTP response has started
loading, is reflected in the DOM, and will be visible in subsequent
draws. This callback occurs early in the document loading process, and
as such you should expect that linked resources (for example, CSS and
images) may not be available.
You can try the following code:
public override void OnPageCommitVisible(WebView view, string url)
{
string _javascript = "const elements =
document.getElementsByClassName('footer-section'); for(i=0;i<elements.length;i++) {
if(elements[i] != null){ elements[i].parentNode.removeChild(elements[i]); }}";
view.EvaluateJavascript(_javascript, null);
base.OnPageCommitVisible(view, url);
}

Related

Why ion-infinite-scroll keeps calling on scrolling in Android?

I am using 'ion-infinite-scroll' in html to load more items from server for this i am using below code
<ion-infinite-scroll immediate-check="false" on-infinite="getListOfAreas()" distance="1%">
</ion-infinite-scroll>
Here, getListOfAreas() function is called when I scroll screen to bottom and it fetches data from server.This is getListOfAreas() function defined on controller
$scope.getListOfAreas = function (shoudlShowLoader) {
AreaBusiness.getAreasListing(shoudlShowLoader, function(serviceResponse) {
$scope.$broadcast('scroll.infiniteScrollComplete');
if (serviceResponse != null) {
var isSuccess = serviceResponse.Success;
if (isSuccess) {
}
}
}
}
On browser, i have debugged some how
$scope.$broadcast('scroll.infiniteScrollComplete');
above line of code keeps calling and spinner keep rotating.I don't know the reason. Am I missing anything?
$scope.$broadcast('scroll.infiniteScrollComplete'); only lets ionic know that the current page of data has been fetched and that it's safe to now fetch the next page. This does not indicate that all data has finished loading.
Looks like the official recommendation is to add an ng-if to the scroll delegate and remove it from dom once there is not more data to load.
Example:
<ion-infinite-scroll
ng-if="moreDataCanBeLoaded()"
icon="ion-loading-c"
on-infinite="loadMoreData()">
</ion-infinite-scroll>
Source: https://ionicframework.com/docs/api/directive/ionInfiniteScroll/
I have resolved the issue, after spending sometime. The issue which I found, I was not adding those elements into the list which were to be shown on UI. So, list was not being updated on controller that is why it kept calling.So I updated my code and added those fetched items from service to list associated to ui as mentioned in my below code
$scope.$broadcast('scroll.infiniteScrollComplete');
if (serviceResponse != null) {
var isSuccess = serviceResponse.Success;
if (isSuccess) {
if ($scope.areas != undefined && $scope.areas.length > 0) {
pushDataToPOIList(serviceResponse.PointOfInterestData);
} else {
$scope.areas = serviceResponse.PointOfInterestData;
}
pushDataToVehiclesList() method I added that is pushing new data into list to update list and on UI as well. This helped me to sort out the problem.

Android onOverrideUrlLoading based on javascript return value

I am working on a hybrid app and trying to return true or false in onOverrideUrlLoading of webview based on returned value from javascript function executed in webview
Example code I have so far.
//Have a boolean variable isExternalDomain;
//Added JavascriptInterface webView.addJavascriptInterface(this, "android");
public boolean onOverrideUrlLoading(final String url) {
WebView.loadUrl("javascript:android.onData('true')");
//I Tried inserting sleep, delay EG: Thread.sleep(200);
//I see the delay but still javascript executes last.
if(isExternalDomain) {
return true;
} else {
return false;
}
}
#JavascriptInterface public void onData(String value)
{
isExternalDomain = true;
}
So the Issue I am having is javascript execution happens after onOverrideUrlLoading completed executing all lines with isExternalDomain as false. I would like to have onOverrideUrlLoading returning true or false based on javascript returned value.
Unfortunately, running JavaScript code from inside onOverrideUrlLoading() isn't possible. You must return from onOverrideUrlLoading() before WebView can do anything else. When you call WebView.loadUrl() from inside onOverrideUrlLoading(), what really happens is an asynchronous task gets posted onto the WebView's message loop. It only gets processed after you leave onOverrideUrlLoading(). Thus, no amount of delay will make WebView to process your request while your code is inside onOverrideUrlLoading().
If you want to prevent navigation from happening based on the decision made by JavaScript code, it's more natural to do that on the JavaScript side by using window.onbeforeunload event handler. If you return non-null value from it, an attempt to navigate away by clicking a link will be cancelled.
Below is a sample of JavaScript code:
window.onbeforeunload = function() {
if (navigationDisallowed()) {
return true; // Prevent navigating away from the page.
} else {
return null; // Allow navigating away.
}
}

How to establish communication between webview and html page in worklight?

I'm working on making a browser as a hybrid app using worklight framework for Android. I implemented my address bar as an input element which received the user input and pass the arguments to the webview to load the page.
However, I cannot figure out how to do the reverse: whenever the user click on a link in webview, I want the address bar to change to the new location.
Are you implementing a native page that is opened? If so, take a look at ChildBrowser, that basically does the same thing. It has a TextView being used as an address bar. You may decide to use it, or get the bits and pieces you want out of it. Regardless, I would image what you want to do something like this. By overriding the onLoadResource in the WebViewClient, you should be able to grab the url and change your TextBox.
In response to the comment below: inside your environment's main js file in the wlEnvInit() function:
function wlEnvInit(){
wlCommonInit();
// Environment initialization code goes here
document.onclick=manageLinks;
}
Then in this function get the url and set the text of your input element:
function manageLinks(event) {
var link = event.target;
//go up the family tree until we find the A tag
while (link && link.tagName != 'A') {
link = link.parentNode;
}
if (link) {
var url = link.href;
console.log("url = " + url);
//You can decide if you want to separate external or
//internal links, depending on your application
var linkIsExternal = ((url.indexOf('http://') == 0) || (url.indexOf('https://') == 0));
if (linkIsExternal) {
myInput.setText(url);
return false;
}
}
return true;
}
Inside of your WebView, inside the plugin, intercept the URL like this:
webview.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
//use this area to set your input. Depending on how you
//implemented your plugin, you may need to return this value
//back to your main activity
Toast.makeText(cordova.getActivity(), "Loading: " + url, Toast.LENGTH_LONG).show();
}
});
Have you try to get the url from the href of and assign to the input variable and do the get/post? I know that it is possible in SDK i figure it dont will be harder in a framework. You can store the hiperlinks in a array with a parser or something similar.
example pseudocode:
When_hiperlink_clicked: //could be like a listener (search about it)
url = hiperlink.getURL("myHiperlink");
myinput.setText(url);
execute_input_bar_action();
Is difficult to figure out without code or something more, sorry.

What is considered onPageFinished in the Android WebViewClient?

I am trying to perform an action on an Android WebView after my webpage finishes loading in it. I setup my WebView to have a WebViewClient to make use of the onPageFinished event callback. However, after some testing, it does't seem to wait until all the JS on the page is done loading before my onPageFinished code fires.
The Google documentation says this:
public void onPageFinished (WebView view, String url)
Added in API level 1
Notify the host application that a page has finished loading. This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet. To get the notification for the new Picture, use onNewPicture(WebView, Picture).
Parameters
view The WebView that is initiating the callback.
url The url of the page.
1) Does onPageFinished only wait for the DOM to load?
2) Is there a way to detect when any JS on the page finishes? If so, what should I use?
I don't see anything in WebViewClient that would be for that purpose. I don't want to add a delay since my users can be on EDGE or on LTE.
You need to implement the callbacks from WebChromeClient. The onPageFinished() is an API that is provided by WebViewClient. There is yet another interface named WebChromeClient that provides the progress information you are seeking:
http://developer.android.com/reference/android/webkit/WebChromeClient.html#onProgressChanged(android.webkit.WebView, int)
Open the link above and look for onProgressChanged(WebView view, int newProgress) - the 'newProgress' variable gives you the percentage of page load that was completed. When it reaches 100 you have a valid page. onPageFinished() cannot be reliably used for this (due to server side redirections etc)
I don't know what you mean by "when JS on the page is finished". Maybe you can clarify what you meant?
From:
https://chromium.googlesource.com/chromium/src.git/+/master/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
#Override
public void didFinishNavigation(final String url, boolean isInMainFrame, boolean isErrorPage,
boolean hasCommitted, boolean isSameDocument, boolean isFragmentNavigation,
Integer pageTransition, int errorCode, String errorDescription, int httpStatusCode) {
...
if (client != null && isFragmentNavigation) {
client.getCallbackHelper().postOnPageFinished(url);
}
}
#Override
public void didFailLoad(
boolean isMainFrame, int errorCode, String description, String failingUrl) {
AwContentsClient client = mAwContentsClient.get();
if (client == null) return;
String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl();
boolean isErrorUrl =
unreachableWebDataUrl != null && unreachableWebDataUrl.equals(failingUrl);
if (isMainFrame && !isErrorUrl && errorCode == NetError.ERR_ABORTED) {
// Need to call onPageFinished for backwards compatibility with the classic webview.
// See also AwContents.IoThreadClientImpl.onReceivedError.
client.getCallbackHelper().postOnPageFinished(failingUrl);
}
}
#Override
public void didStopLoading(String validatedUrl) {
if (validatedUrl.length() == 0) validatedUrl = ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL;
AwContentsClient client = getClientIfNeedToFireCallback(validatedUrl);
if (client != null && validatedUrl.equals(mLastDidFinishLoadUrl)) {
client.getCallbackHelper().postOnPageFinished(validatedUrl);
mLastDidFinishLoadUrl = null;
}
}
We can easily see that onPageFinished is not pretty much what you're expecting.
To answer your first question: I have found that onProgressChanged will not reach 100, and onPageFinished will not be called until all of the assets (css/js/images) have finished loading for that page.
I can not, however, find any official documentation that states that.

PhoneGap 1.0.0 - Android 2.1/2.3 - Not able to make a phonegap plugin to work asynchronously

What I'm trying to do:
user fills out a form data, clicks submit.
user presented with a loading screen. (HTML element).
Application makes asynchronous call, PhoneGap plugin, which saves this data in db. That's where the problem is, because the call is synchronous instead.
When html app receives a callback, I hide loading screen.
Because of synchronous call that's what I got:
user fills out a form, submits
HTML app freezes, data is being saved to a database.
loading screen appears
callback is called, a few milliseconds after.
Here's some demo (trimmed) code:
Java:
public class SomePlugin extends Plugin
...
public PluginResult execute(String action, JSONArray data, String callbackId)
{
PluginResult result = null;
//
// save data in the background...
//
Log.d("TAG", "Some Message...");
result = new PluginResult(Status.OK, "");
// or
// result = new PluginResult(Status.ERROR);
return result;
}
...
public boolean isSynch(String action) {
return false; // always do async...
}
JavaScript:
$('#loading-screen').show();
var successCallback = function() {
console.log('Success Callback');
$('#loading-screen').hide();
};
var failureCallback = function() {
console.log('Failed Callback');
$('#loading-screen').hide();
};
PhoneGap.exec(successCallback, failureCallback, 'PluginName', 'actionName', data);
From PhoneGap source:
* Execute a PhoneGap command. It is up to the native side whether this action is synch or async.
* The native side can return:
* Synchronous: PluginResult object as a JSON string
* Asynchrounous: Empty string ""
* If async, the native side will PhoneGap.callbackSuccess or PhoneGap.callbackError,
* depending upon the result of the action.
So I thought maybe this line is incorrect in that case:
new PluginResult(Status.OK, "");
Note: If wrap (JavaScript) PhoneGap.exec call in setTimeout (with a delay of 1 sec for example), loading screen will work "properly" (it's still frozen but user have an instant feedback), but that's obviously not a solution.
I think I just not seeing something obvious here, just one parameter or something somewhere.
Thanks.
I think its perfect for an AsyncTask
just process you dbStorage in doInBackground and handle finishing in onPostExcecute().
You are free to update status in onProgressUpdate

Categories

Resources