I faced the following problem. There's a part of the webpage:
document.getElementById('continueButton').addEventListener('click', function () {
window.parent.postMessage('PAYLANDS-ERROR', '*');
if (window.parent.HTMLOUT) {
window.parent.HTMLOUT.paylandsFail();
}
});
Here's my interface which contains methods with annotation #JavascriptInterface:
interface IAddCard3dsJavaScript {
#JavascriptInterface
fun paylandsSuccess()
#JavascriptInterface
fun paylandsFail()
companion object {
const val INTERFACE_NAME = "HTMLOUT"
}
}
There's the class which implements this interface:
class AddCard3dsJavaScript(private val presenter: IAddCard3dsCallback) : IAddCard3dsJavaScript {
override fun paylandsSuccess() {
presenter.onPaylands3dsSuccess()
}
override fun paylandsFail() {
presenter.onPaylands3dsFailed()
}
}
But when I run the app I get this line in console: Uncaught TypeError: window.parent.HTMLOUT.paylandsFail is not a function. I tried to change the interface name to window.parent.HTMLOUT instead of HTMLOUT, and in this case, I didn't get the error, but paylandsFail method body didn't execute. So, what's the problem and how can I solve it?
UPD
Here's the way how I add this interface to webview:
#SuppressLint("JavascriptInterface")
override fun loadUrlFor3ds(url: String) {
addCardWebView?.apply {
addJavascriptInterface(AddCard3dsJavaScript(getController()), IAddCard3dsJavaScript.INTERFACE_NAME)
loadUrl(url)
}
}
Fixed by adding annotation #JavascriptInterface to AddCard3dsJavaScript - IAddCard3dsJavaScript implementation
Related
I want to do something like this in a razor page:
#if (currentwidth<x)
{
le code
}
else
{
le other code
}
I have added javascript file and connected it to a utility service which works when I get the static width (which I tested).
js:
export function getCurrentWidth() {
return window.addEventListener("resize", () => {
window.innerWidth;
});
}
UtilityService method:
public async Task<double> GetCurrentWidth()
{
var m = await GetModule();
var result = await m.InvokeAsync<double>("getCurrentWidth");
return result;
}
Razor file:
double width;
protected async override Task OnInitializedAsync()
{
width = await utilityService.GetCurrentWidth();
}
Thus the problem is I can't call it from OnInitailzedAsync since this function only fired once, so I need a function that constantly checks the GetCurrentWIdth() method to check for resize.
Is there another way of doing this in blazor or what method could I use/ Thank you in advance.
First of all I'd like to point out that you may not have to solve your problem with javascript/C# code. If it's something in the html that you want to manipulate, you may just be better of using css. But I'll leave that up to you.
If however you truly need the window width like you mentioned above, then I would recommend registering a listener to the window (as you've already done) and have that listener call a dotnet function. Doing this with static methods is quite easy, but for instance component this can be a bit trickier as you have to pass an object reference of the current object.
The [JsInvokable] indicates that this method can be called from javascript, which allows communication from the javascript event listener to dotnet.
CSharpFromJs.razor.cs
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Threading.Tasks;
public partial class CSharpFromJS
{
private DotNetObjectReference<CSharpFromJS> _objectReference;
public int WindowWidth { get; set; }
[Inject]
public IJSRuntime JSRuntime { get; set; }
protected override void OnInitialized()
{
_objectReference = DotNetObjectReference.Create(this);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await InitWindowWidthListener();
}
}
[JSInvokable]
public void UpdateWindowWidth(int windowWidth)
{
WindowWidth = windowWidth;
StateHasChanged();
}
private async Task InitWindowWidthListener()
{
await JSRuntime.InvokeVoidAsync("AddWindowWidthListener", _objectReference);
}
public async ValueTask DisposeAsync()
{
await JSRuntime.InvokeVoidAsync("RemoveWindowWidthListener", _objectReference);
_objectReference?.Dispose();
}
}
CSharpFromJs.razor
#implements IAsyncDisposable
<h1>Window width: #WindowWidth</h1>
Javascript
// Manages the registered event listeners so they can be disposed later
let windowEventListeners = {};
function AddWindowWidthListener(objReference) {
let eventListener = () => UpdateWindowWidth(objReference);
window.addEventListener("resize", eventListener);
windowEventListeners[objReference] = eventListener;
}
function RemoveWindowWidthListener(objReference) {
window.removeEventListener("resize", windowEventListeners[objReference]);
}
function UpdateWindowWidth(objReference) {
objReference.invokeMethodAsync("UpdateWindowWidth", window.innerWidth);
}
The only thing you should be careful with is when a component is disposd. You should remove the registered handlers in the DisposeAsync function to ensure that they're not still registered to prevent memory leaks.
This link might provide some better instructions on how to use this, but they don't explain the part about disposing handlers.
Note: This only works in .net5 and later, as IAsyncDisposable was not yet implemented for component before that. If for some reason you're working with an earlier version, you could call it using IDisposable. But this could potentially cause deadlocks, so I would not recommend it.
For me works the NuGet package BlazorPro.BlazorSize
Implement the method:
async void WindowResized(object _, BrowserWindowSize window){}
and all necessary Dependencies (see description).
Hi team im have a very small question, i have this code:
constructor(private mapper: any, private applyCallback: (arg0: INode) => void) {
super()
/** #type {GanttMapper} */
this.mapper = new GanttMapper(datamodel);
/** #type {function(INode):void} */
this.applyCallback = applyCallback;
// create the dummy node
this.dummyNode = new SimpleNode();
// switch off the default template
//type RouterClass = typeof ;
//interface RouterDerived extends RouterClass { }
console.log("routerClass");
this.template = new IVisualTemplate({
createVisual() {
return null;
},
updateVisual() {
return null;
}
});}
but in the part:
this.template = new IVisualTemplate({
createVisual() {
return null;
},
updateVisual() {
return null;
}
});
im have an error and the error is this: Cannot create an instance of an abstrac class
in JS this code is working fine but im trying to migrate it in angular and is not working.
im read the other part of same issues but i cant solved it......
im try all tipes of replays but is not working.
Thanks all.
This is because Angular (or rather TypeScript) is more strict than JavaScript. There are things you can do in JavaScript that cannot properly be expressed in a TypeScript definition file, without weakening the type-checks.
This is one of those things. It will work at runtime, but the TypeScript compiler does not understand this feature and will warn you not to use that unrecognized construct.
It's a feature, unique to the yFiles class library and it's called quick interface implementation.
The documentation also states this:
Quick Interface Implementation in TypeScript
The TypeScript .d.ts file doesn’t contain typings that allow quick interface implementations. They still work at runtime, but the TypeScript compiler will produce an error nonetheless. To work around this issue, you can either tell the compiler to ignore the offending line, or use an anonymous implementation of the interface:
// #ts-ignore
const customHitTestable = new IHitTestable((context, location) => location.x > 25)
const customVisualCreator = new class extends BaseClass<IVisualCreator>(IVisualCreator) {
createVisual(context: IRenderContext): Visual {
return new SvgVisual(document.createElementNS("http://www.w3.org/2000/svg", "g"))
}
updateVisual(context: IRenderContext, oldVisual: Visual): Visual {
return oldVisual
}
}
In newer version of yFiles for HTML (since 2.3), there is now a convenient short-hand that works great with typescript:
const customHitTestable = IHitTestable.create((context, location) => location.x > 25)
This does not require the ts-ignore and works for all interfaces: If there is only one method in the interface, all you need to do is pass its implementation to the .create method on the interface object. If there are more members, they need to be passed in via an option object with the names of the members. The typescript definition file provides full completion for this usecase, now.
{
createVisual() {
return null;
},
updateVisual() {
return null;
}
}
This is not valid JavaScript, try
{
createVisual: () => {
return null;
},
updateVisual: () => {
return null;
}
}
here is the code of IVisualTempleate
I looking for a way to inherit from WebElement object that webdriverio returns, without monkey-patching and with TS types support (autocompletion is a must). Is there a way to do something like this?
class Checkbox extends WebdriverIOWebElement {
constructor() {
super($('div'))
}
// overriding base method
isDisplayed(): boolean {
// blabla some new logic here
}
check() {
if(!this.isChecked()) {
this.click()
}
}
uncheck() {
if(this.isChecked()) {
this.click()
}
}
}
Lets take an example , When we have a New Tag (my-app) in HTML and we have to build a case to Login using webdriverIO ,
Assume this is the HTML :
What we would do is using the component object pattern , component object pattern attempts to reduce that repetition and move the component's api into an object of its own. We know that in order to interact with an element's shadow DOM, we first need the host element. Using a base class for your component objects makes this pretty straightforward.
Here's a bare-bones component base class that takes the host element in its constructor and unrolls that element's queries up to the browser object, so it can be reused in many page objects (or other component objects), without having to know anything about the page itself.
class Component {
constructor(host) {
const selectors = [];
// Crawl back to the browser object, and cache all selectors
while (host.elementId && host.parent) {
selectors.push(host.selector);
host = host.parent;
}
selectors.reverse();
this.selectors_ = selectors;
}
get host() {
// Beginning with the browser object, reselect each element
return this.selectors_.reduce((element, selector) => element.$(selector), browser);
}
}
module.exports = Component;
then what we would do is , We will write a subclass for our app-login component:
const Component = require('./component');
class Login extends Component {
get usernameInput() {
return this.host.shadow$('input #username');
}
get passwordInput() {
return this.host.shadow$('input[type=password]');
}
get submitButton() {
return this.login.shadow$('button[type=submit]');
}
login(username, password) {
this.usernameInput.setValue(username);
this.passwordInput.setValue(password);
this.submitButton.click();
}
}
module.exports = Login;
Finally, we can use the component object inside our login page object:
const Login = require('./components/login');
class LoginPage {
open() {
browser.url('/login');
}
get app() {
return browser.$('my-app');
}
get loginComponent() {
// return a new instance of our login component object
return new Login(this.app.$('app-login'));
}
}
Now this component object can now be used in tests for any page or section of your app that uses an app-login web component, without having to know about how that component is structured. If you later decide to change the internal structure of the web component, you only need to update the component object.
Now we apply the same approach with the Check Box Component by using Shadow Dom Support :
public class CheckBox extends Component {
public CheckBox(element) {
this.element = element;
}
get checkBoxSelector() {
return this.host.shadow$(element);
}
get void toggle() {
checkBoxSelector().click();
}
get void check() {
if (!isChecked()) {
toggle();
}
}
get void uncheck() {
if (isChecked()) {
toggle();
}
}
get boolean isChecked() {
return checkBoxSelector().isSelected();
}
}
Then We can write a Check Box Controller component that can get the instance of check box using id and verify what every is necessary.
const CheckBox= require('./components/CheckBox');
class CheckBoxController{
open() {
browser.url('/login');
}
get checkboxComponent() {
// Using this we can verify whether the Specific Check Box has been Selected or Not
let element = browser.$('[id="lpagecheckbox"]');
return new CheckBox(element);
}
}
Note :
Please bear this is not the actual code , This is just a part of the template which can help us to move towards the solution of the Problem .
Source Contends :
https://webdriver.io/docs/api/element/isSelected.html
https://webdriver.io/blog/2019/02/22/shadow-dom-support.html
https://webdriver.io/blog/2019/04/03/react-selectors.html
https://webdriver.io/docs/pageobjects.html
Moreover if we are using Selenium Webdriver , This can help us to Achieve it
Here we have an interface which actually combines all the webdriver interfaces , then we create a Specific implementation by inheriting the Element Class , finally Lets assume of any component you need we should be inheriting and using it with its own implementation , In this case lets assume the Check box that should be inherited from then Element Implementation Class and finally a Cranky way of using it by instantiating the object. CheckBox cb = new CheckBox(element);cb.uncheck();
Step 1:
Create an Interface that combines all of the WebDriver interfaces:
public interface Element extends WebElement, WrapsElement, Locatable {}
Step 2:
Element Implementation Inheriting the element class:
public class ElementImpl implements Element {
private final WebElement element;
public ElementImpl(final WebElement element) {
this.element = element;
}
#Override
public void click() {
element.click();
}
#Override
public void sendKeys(CharSequence... keysToSend) {
element.sendKeys(keysToSend);
}
// And so on, delegates all the way down...
}
Step 3:
Consider any component you use , Lets assume Check Box in this case
public class CheckBox extends ElementImpl {
public CheckBox(WebElement element) {
super(element);
}
public void toggle() {
getWrappedElement().click();
}
public void check() {
if (!isChecked()) {
toggle();
}
}
public void uncheck() {
if (isChecked()) {
toggle();
}
}
public boolean isChecked() {
return getWrappedElement().isSelected();
}
}
Way of Using It :
CheckBox cb = new CheckBox(element);
cb.uncheck();
If you want More Clear way of Implementing Something Like this : refer the third Link
public class Part2ExampleTest {
private final WebDriver driver;
#FindBy(id = "checkbox")
CheckBox checkBox;
protected Part2ExampleTest(WebDriver driver) {
this.driver = driver;
}
protected static Part2ExampleTest initialize(WebDriver driver) {
return ElementFactory.initElements(driver, Part2ExampleTest.class);
}
#Test
public void simple() {
WebDriver driver = new FirefoxDriver();
Part2ExampleTest page = initialize(driver);
PageLoader.get(driver, "forms.html");
Assert.assertFalse(page.checkBox.isChecked());
page.checkBox.check();
Assert.assertTrue(page.checkBox.isChecked());
driver.close();
}
}
Sources :
Extend Selenium WebDriver WebElement?
http://elisarver.com/2012/12/09/wrapping-webelement-1/
http://elisarver.com/2012/12/10/wrapping-webelement-2
IWebElement is an interface that you can just implement inside your driver class.
Greetings fellow Earthicans,
The following code is used on my website: brianjenkins94.me in order to handle baseline navigation functionality and while it was working previously I decided to leverage the class-based approach provided by the TypeScript Language in order to structure my code in a more readable fashion. In doing so I seem to have broken the functionality and now all #nav.on("click") events trigger the error Uncaught TypeError: Cannot read property 'removeClass' of undefined on Line 54 (see comment in code).
If anyone could identify why this code is nonfunctional or perhaps provide some insight as to whether there is a better way of going about doing this, (I'm really interested in proper design and right practice, the bug is just a convenient excuse to make a post and get input) it would be greatly appreciated.
Thanks ahead of time,
Brian
/// <reference path="jquery.d.ts" />
"use strict";
class Main {
//private SERVERNAME: string = "http://brianjenkins94.me/";
//private DOCUMENTROOT: string = "https://rawgit.com/brianjenkins94/local.blog.com/master/"
public init(): void {
$(function(): void {
var Nav: Navigation = new Navigation($("body"), $("#nav"), $("a[href=\"#nav\"]"));
Nav.init();
});
}
}
class Navigation {
private body: JQuery;
private nav: JQuery;
private navToggle: JQuery;
private navClose: JQuery = $("<a></a>");
constructor(bodyInit: JQuery, navInit: JQuery, navToggleInit: JQuery) {
this.body = bodyInit;
this.nav = navInit;
this.navToggle = navToggleInit;
// Create navClose element
this.navClose.attr({
href: "#",
tabIndex: 0
});
(this.navClose).addClass("close");
(this.nav).append(this.navClose);
};
public init(): void {
this.disablePropogation();
this.clickListener(this.body);
this.clickListener(this.navToggle);
this.clickListener(this.navClose);
this.clickListener(this.nav);
this.keyCodeListener();
}
private disablePropogation(): void {
(this.nav).on("click touchend", function(event: Event): void {
event.stopPropagation();
});
}
private clickListener(target: JQuery): void {
(target).on("click touchend", function(): void {
if (!(target === (this.body))) {
event.preventDefault();
event.stopPropagation();
if (target === this.navToggle) {
(this.nav).toggleClass("visible");
return;
}
}
(this.nav).removeClass("visible"); // They call me, line 54
});
}
private keyCodeListener(): void {
$(window).on("keydown", function(event: JQueryKeyEventObject): void {
if (event.keyCode === 27) {
(this.nav).removeClass("visible");
}
});
}
}
var main: Main = new Main();
main.init();
this is of the wrong type (window) and not the instance of the class. The best way to fix It is by using an Arrow function to capture the this reference like below:
private clickListener(target: JQuery): void {
(target).on("click touchend", () => {
if (!(target === (this.body))) {
event.preventDefault();
event.stopPropagation();
if (target === this.navToggle) {
(this.nav).toggleClass("visible");
return;
}
}
(this.nav).removeClass("visible"); // They call me, line 54
});
}
Check out the generated code on what it actually does. If you also want to use this provided by jQuery (the element in this case) you can also do
var that = this;
Right above the on call and use that for the class and this for your jQuery target. This is similar to what the arrow function generates but that generates _this instead of "that".
edit if you need to keep TSLint happy you should probably do () :void => { in the arrow function
I'am having a flex web project and i need to use some java script functions (e.g,geolocation) so can anyone help me to understand the way of relating them to each others.
The ExternalInterface class is used for communication between swf's and the javascripts located on the same page.
By using the ExternalInterface.call("functionName", functionParams...) function in as3 you can call any function in javascript within your webpage.
To register functions to be called in flex from javascript use ExternalInterface.addCallback("functionName", functionReference).
Usage:
package {
import flash.display.MovieClip;
import flash.external.ExternalInterface;
public class EITest extends MovieClip {
public function EITest() {
registerWithJavascript();
makeCall();
}
public function registerWithJavascript():void {
// To register a function with javascript
var isAvailable:Boolean = ExternalInterface.available;
if(isAvailable)
ExternalInterface.addCallback("callbackName", actualCallback);
}
public function actualCallback():void {
// Do something
}
public function makeCall():void {
// To call a javascript function
var isAvailable:Boolean = ExternalInterface.available;
var someParamToSend:int = 13;
if(isAvailable)
ExternalInterface.call("someFunction", someParamToSend);
}
}
}