WebView.InvokeScriptAsync not working in universal app - javascript

I am using a webview to display a certain html file, However, when I call InvokeScriptAsync, I keep encountering the error.
"Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))". This occurs eventhough the script is called in NavigationComplete or DOMContentLoaded.
I prepared a simple app to debug this problem and I noticed that when the script is in a separate .js file, the error occurs. But if it is placed in the html file, the error would not occur.
I am hoping to have the script in a separate file since I have a quite a lot of functions to implement and I would be using some third party scripts so it would not be maintainable having all the scripts on the html file.
BTW, I did try the same code in a non-universal app and just used Windows 8.1 store app and it would work correctly even with the script stored in a separate file. That is why there must be some setting I am missing to make this work in a universal app.
This is my MainPage code:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
MapWebView.NavigationCompleted +=MapWebView_NavigationCompleted;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Uri url = new Uri("ms-appx-web:///Common/Web/SamplePage.html");
MapWebView.Navigate(url);
}
private async void MapWebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
try
{
await MapWebView.InvokeScriptAsync("SayHello", new string[] { "Hello! This is a test parameter" });
}
catch(Exception e)
{
string error = e.Message;
}
}
}
NOT WORKING (script is in a separate file which is sample.js):
html file:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script type="text/javascript" src="sample.js"></script>
<p>Parameter From Script File:</p> <div id="paramDiv"></div>
</body>
</html>
sample.js file:
function SayHello(parameter)
{
document.getElementById('paramDiv').innerHTML = parameter;
}
WORKING (script is in the html file):
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script>
function SayHello(parameter) {
document.getElementById('paramDiv').innerHTML = parameter;
}
</script>
<p>Parameter From Script File:</p> <div id="paramDiv"></div>
</body>
</html>
Here is the setup of my project:
I have my project setup as a universal app. In the shared code part of the universal app, I have the following files
Common (folder)
Web
SamplePage.html
sample.js

I found the solution to this problem after wasting my whole day on it.
It is caused by incorrect tagging of javascript files in *.Shared.projitem.
The javascript files are tagged as NONE in the ItemGroup which seems to cause it not being found. To make it visible to the project, change it to Content.
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)Common\Web\sample.js" />
</ItemGroup>
Kindly refer to this link where I also posted the solution.
https://social.msdn.microsoft.com/Forums/windowsapps/en-US/b29feddb-ae39-4580-9114-43839aabbcf2/webviewinvokescriptasync-not-working-in-universal-app?forum=winappswithcsharp

Related

Using html code with a javascript code as a widget in flutter web

I am currently using flutter web and I already have an html button that I want to add inside my flutter app. This html contains a java script as its body. How to add the html with javascript as a widget inside my app? This is the html snippet:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Paytabs Express Checkout V4</title>
</head>
<body>
<script
src="https://paytabs.com/express/v4/paytabs-express-checkout.js"
id="paytabs-express-checkout"
data-secret-key="key"
data-ui-type="button"
data-merchant-id="mid"
data-url-redirect="https://my09713z28.codesandbox.io/"
data-amount="3.3"
data-currency="SAR"
data-title="John Doe"
data-product-names="click"
data-order-id="25"
data-ui-show-header="true"
data-customer-phone-number="5486253"
data-customer-email-address="john.deo#paytabs.com"
data-customer-country-code="973"
data-ui-show-billing-address="false"
data-billing-full-address="test test test"
data-billing-city="test"
data-billing-state="test"
data-billing-country="BHR"
data-billing-postal-code="123"
></script>
<script>
</script>
</body>
</html>
Hope you provide me with some help.
You can go something like this. You should put your html releated code in index.html file and in src you need to put a path for your index.html e.g. 'assets/index.html'
import 'dart:html' as html;
import 'dart:js' as js;
import 'dart:ui' as ui;
String viewID = "your-view-id";
#override
Widget build(BuildContext context) {
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
viewID,
(int id) => html.IFrameElement()
..width = MediaQuery.of(context).size.width.toString()
..height = MediaQuery.of(context).size.height.toString()
..src = 'path/to/your/index.html'
..style.border = 'none');
return SizedBox(
height: 500,
child: HtmlElementView(
viewType: viewID,
),
);
}
You can use HtmlElementView for adding html elements inside a flutter web app
https://api.flutter.dev/flutter/widgets/HtmlElementView-class.html
Beware that would only work in flutter web and
Embedding HTML is an expensive operation and should be avoided when a
Flutter equivalent is possible
You should add this html content inside the file web/main.html.
I suggest you to build the button with Flutter and call javascript code with dart like this example calling javascript from Dart
If I understand correctly, your intention is to be able to render your html/javascript as a native widget in flutter.
Unfortunately, I don't think this is technically possible due to the fact that flutter is rendering everything in its own light-weight rendering engine, rather than creating native code that your native runtime executes. The artifact(s) created (even in flutter web) after compilation is a combination of flutter runtime + your compiled code that executes on flutter runtime. Therefore this is not possible to add html/javascript to your flutter code as a widget and run it everywhere.
The solution is to implement your widget in pure Dart code.

Controller received 2 request for every page request

I have modified the Map Route in my Dot Net Core application that for every request goes to one controller, so not lots of controller or Action Result is needed for each page that we build.
greedy Routing
routes.MapRoute("", "/{*article}",
defaults: new { controller = "Pages", action = "Killme" });
In Page Controller build an object that has list of CSS and JavaScript locations, this object is being passed to Page view
public IActionResult Killme()
{
var PageInfo = GetPage_Data();
ViewBag.PageInfo = t;
return View("Pages");
}
and i have tried to pass this information as model or view bag to Page view.
in the Page view i try to build the JavaScript and CSS dynamically based on the model like
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
#{
RootObject PageInfo = ViewBag.PageInfo;
foreach (var JavaScript in PageInfo.js)
{
var JSsrc = JavaScript.src;
<script type="text/javascript" src="#JSsrc ">
</script>
}
<script type="text/javascript" src=""></script>
</head>
<body>
</body>
</html>
Now the Issue is when i build the JavaScript the controller is called 2 times and the page is being rendered 2 times, when i comment the
<script type="text/javascript" src="#JSsrc ">
</script>
the page controller will get called once,
any help regarding why this happening and what am i doing wrong would be appreciated
The reason for this behavior is that the staticFileHandler is either not configured or is not able to find your Javascript file and passes the request further down the pipeline. The MVC handler captures all requests (because of your route) and returns therefore the same page again.
First check that your startup class uses the staticFileHandler before the mvcHandler, so something like this:
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();
..
app.UseMvc();
}
}
Secondly make sure that your Javascript is placed inside the wwwroot and uses the correct path.So a file like wwwroot/js/mysite.js should a script tag like:
<script src="/js/mysite.js"></script>
These improvements should resolve your issue.

Simple AngularJS 1.5.9 Component Not Rendering in MVC 5

I am trying to get AngularJS 1.5.9 up and running an MVC 5 application using a very simple component called configuration-list.
I created an MVC 5 application (4.5.2), added the Angular.Core 1.5.9 Nuget package
To take MVC 5, layout and razor rendering out of the picture, I created a simple file called test.htm:
<!DOCTYPE html>
<html ng-app>
<head>
<title></title>
<meta charset="utf-8" />
<script src="Scripts/angular.js"></script>
<script src="Scripts/app/module.js"></script>
</head>
<body>
<configuration-list></configuration-list>
</body>
</html>
And in module.js:
(function () {
"use strict";
angular.module("radar", []).component("configuration-list", {
template: "Hello from configuration list"
});
}());
The browser (IE 11) comes up empty.
I have opened the debugging tools and go to the console tab, and there are no errors logged.
I have put a breakpoint in module.js and it is hit (so I know the code is running)
I have tried moving the scripts below the component in the body tag
I have tried setting ng-app="radar" in the html tag
Any idea what I'm missing?
For components the naming has to be camelcase, not hyphencase
angular.module("radar", []).component("configurationList", {
template: "Hello from configuration list"
});

Problems with SkyScanner Widget in webpage

I am following this example to include a SkyScanner widget on my website:
http://business.skyscanner.net/portal/en-GB/Documentation/Widgets
For some reason I just get an empty div - could this be something to do with the key? When I clicked on the activation link I got from SkyScanner for the widget key, I got a page saying the following:
Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed remotely (for security reasons). It could, however, be viewed by browsers running on the local server machine.
Details: To enable the details of this specific error message to be
viewable on remote machines, please create a tag within
a "web.config" configuration file located in the root directory of the
current web application. This tag should then have its
"mode" attribute set to "Off".
I have created a web.config file with the following code:
<!-- Web.Config Configuration File -->
<configuration>
<system.web>
<customErrors mode="Off"/>
</system.web>
</configuration>
I've had a look at 'inspect element' on Chrome and get the error
Uncaught TypeError: Object # has no method 'write'
api.ashx?key=[KEY]:1
This is the JS:
var API_KEY = 'b7290ac3-1f9f-4575-88a7-89fed0c61f7f',
MAIN_URL = 'http://api.skyscanner.net/api.ashx?key=' + API_KEY;
function main(){
console.log('loaded module');
var snippet = new skyscanner.snippets.SearchPanelControl();
snippet.setCurrency('GBP');
snippet.setDeparture('uk');
snippet.draw(document.getElementById('snippet_searchpanel'));
};
function newWrite(str) {
$(str).appendTo('body');
}
var oldWrite = document.write;
document.write = newWrite;
function onMainSkyscannerScriptLoad(e) {
console.log('loaded main script');
skyscanner.loadAndWait('snippets', '1', {'nocss' : true}, main);
}
$('button').click(function() {
console.log('getting main script');
$.getScript(MAIN_URL, onMainSkyscannerScriptLoad);
});
I also used this to personalise the widget:
skyscanner.load("snippets","2");
function main(){
var snippet = new skyscanner.snippets.SearchPanelControl();
snippet.setShape("box300x250");
snippet.setCulture("en-GB");
snippet.setCurrency("USD");
snippet.setColourScheme("classicbluelight");
snippet.setProduct("flights","1");
snippet.setProduct("hotels","2");
snippet.setProduct("carhire","3");
snippet.draw(document.getElementById("snippet_searchpanel"));
}
skyscanner.setOnLoadCallback(main);
Skyscanner B2B support engineer here. Are you still having trouble with this?
For the quickest response, please contact us here: http://business.skyscanner.net/portal/en-GB/Home/Contact
The first thing to check is that the file is on a web server (localhost is fine), and not loaded from the desktop (or local disk in general). This is because some of the Skyscanner JS code looks up other files using URLs like //api.skyscanner.net. In other words, saving the file to the desktop and opening it from there will not work (will show as an empty div). Here's the most basic example of drawing a widget. Can you try putting this in a file and accessing it through a server? If it works we can build on it :)
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" >
<head>
<script type="text/javascript" src="//api.skyscanner.net/api.ashx?key=b7290ac3-1f9f-4575-88a7-89fed0c61f7f"></script>
<script type="text/javascript">
skyscanner.load("snippets","2");
function main(){
var snippet = new skyscanner.snippets.SearchPanelControl();
snippet.setShape("box300x250");
snippet.setCulture("en-GB");
snippet.setCurrency("USD");
snippet.setProduct("flights","1");
snippet.setProduct("hotels","2");
snippet.setProduct("carhire","3");
snippet.draw(document.getElementById("snippet_searchpanel"));
}
skyscanner.setOnLoadCallback(main);
</script>
</head>
<body>
<div id="snippet_searchpanel" style="width: auto; height:auto;"></div>
</body>
</html>

Unobtrusive JavaScript - Separate JS File Not Found

Using the concept unobtrusive JavaScript, I'm trying, for the first time, to place my JavaScript in a separate file from the HTML. But, no matter what I do, I get an error that the file wasn't found.
This is the actual error in the google chrome console (ctrl-shift-j):
GET http://localhost:14385/Home/TestPage.js 404 (Not Found)
I started with a new MVC 4 app. I created a new test page:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html>
<html>
<head runat="server">
<meta name="viewport" content="width=device-width" />
<script src="TestPage.js"></script>
<title></title>
</head>
<body>
<div>
<input id="foo" value="snuh" />
</div>
</body>
</html>
And I created a new TestPage.js in the same folder:
$(document).ready(function() {
function dosomething() {
alert('snuh');
}
document.getElementById('foo').onclick = dosomething;
});
I've tried the tips posted here, but I always get an error that the JavaScript file isn't found. Any idea what's wrong with this simple test?
Note: The TestPage actually displays, with the input box showing.
This is the layout in solution explorer:
Make sure you reference your javascript from the correct location using server side helpers:
<script src="<%= Url.Content("~/TestPage.js") %>"></script>
This will properly reference the javascript file no matter from which location you have rendered this view. It assumes obviously that you have placed your javascript file in the root of your application. The The convention is to use the Scripts folder for this:
<script src="<%= Url.Content("~/Scripts/TestPage.js") %>"></script>
UPDATE:
Now that you have shown your project structure you seem to have placed the TestPage.js file inside the ~/Views folder. This won't work. This folder is not accessible from the client side. It is explicitly forbidden and not served by IIS. You should never place any static files inside. Move your javascript folder to the ~/Scripts folder.
Also you seem to be using jQuery inside your TestPage.js file but you never referenced it so your script won't work. If you want to use jQuery make sure that you have added it as well:
<script src="<%= Url.Content("~/Scripts/jquery-1.8.2.js") %>"></script>
<script src="<%= Url.Content("~/Scripts/TestPage.js") %>"></script>
or if you don't want to use jQuery fix your script so that it doesn't depend on it:
function dosomething() {
alert('snuh');
}
window.onload = function() {
document.getElementById('foo').onclick = dosomething;
};
or if you place your scripts at the end of your DOM you don't even need to wrap them in a document ready handler because at this stage the DOM will be ready and you can manipulate it:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html>
<html>
<head runat="server">
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<div>
<input id="foo" value="snuh" />
</div>
<script src="<%= Url.Content("~/Scripts/TestPage.js") %>"></script>
</body>
</html>
and then inside your script:
function dosomething() {
alert('snuh');
}
document.getElementById('foo').onclick = dosomething;

Categories