I'm have implemented the picture in picture function for my web project on angular.
This is the basic component for it.
export class PlayerPipComponent implements OnInit {
#Input() video!: HTMLVideoElement;
isPlayerErrorOpen = false;
constructor(#Inject(DOCUMENT) private document: Document, private dialog: MatDialog) {}
ngOnInit(): void {}
async togglePip(): Promise<void> {
try {
if (this.document.pictureInPictureEnabled) {
if (this.video !== this.document.pictureInPictureElement) {
await this.video.requestPictureInPicture();
} else {
await this.document.exitPictureInPicture();
}
} else {
this.showGeneralError('000', "This browser doesn't have Picture in Picture enabled.");
}
} catch (error) {
console.log('Error', error);
this.showGeneralError('000', error);
}
}
I was trying to add the controls for seekforward and seekbackward, but for some reason they don't seem to work on it. But the previoustrack and nexttrack controls work fine.
navigator.mediaSession.setActionHandler('previoustrack', (details) => {
// Go to previous track
console.log('previostrack', details);
});
navigator.mediaSession.setActionHandler('nexttrack', (details) => {
// Go to next track
console.log('nextrack', details);
});
Just adding these few lines, it shows the controls in the picture in picture. But if add these next ones, it doesn't show the seekbackward o forward controls.
navigator.mediaSession.setActionHandler('seekbackward', function (details) {
// Do something
});
navigator.mediaSession.setActionHandler('seekforward', function (details) {
//Do something
});
Does anyone know if they are just not supported? Or if you could point out what I'm doing wrong, I would be very thankful.
I have a webpage that I load on a WebViw in flutter and that webpage has a javascript function that I want to run with a parameter from flutter.
I wrote this uderneath, and it looks like it is running the alert function fine, but when I try to run the function that is defined on the webpage javascript it says it is undefined. Why could this be? Also, do you see any other mistakes on my code that I may be missing, despite it working?
class WebViewPageState extends State<WebViewPage> {
final String url;
final String title;
WebViewPageState(this.url, this.title);
final Completer<WebViewController> _controller = Completer<WebViewController>();
late WebViewController _mycontroller;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Column(children: [
Expanded(
child: WebView(
initialUrl: this.url,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webviewcontroller) {
_controller.complete(_mycontroller = webviewcontroller);
},
onPageFinished: (url){
print("Ok we loaded page");
setState(() {
_mycontroller.runJavascriptReturningResult('alert("Hello, World!")');
});
},
))
]));
}
}
runJavascriptReturningResult is trying to get a return value from your javascript and since it's an alert it can't find it. try using _mycontroller.runJavascript('alert("Hello, World!")');
Trying to implement Braintree payment gateway into flutter web.
Still no SDK for flutter web from Braintree. So trying to implement their javascript SDK.
Here is my js file
function payment(auth){
var button = document.querySelector('submit-button');
console.log(auth);
console.log(button);
braintree.dropin.create({
authorization: auth,
container: 'dropin-container'
}, function (createErr, instance) {
console.log(createErr);
console.log(instance);
button.addEventListener('click', function () {
instance.requestPaymentMethod(function (requestPaymentMethodErr, payload) {
// Submit payload.nonce to your server
return payload.nonce
});
});
});
}
Calling this js function from dart. Here is the complete dart code.
#JS()
library my_script;
import 'dart:html';
import 'dart:js_util';
import 'package:carbonbins/model/model.dart';
import 'package:carbonbins/pages/navigation.gr.dart';
import 'package:carbonbins/utils/image_helper.dart';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'package:js/js.dart';
import 'package:js/js.dart' as js;
#JS()
external void initBraintree(auth);
#JS()
external String payment(auth);
class PaymentPage extends StatefulWidget {
final UserModel userModel;
PaymentPage({#required this.userModel});
#override
_PaymentPageState createState() => _PaymentPageState();
}
class _PaymentPageState extends State<PaymentPage> {
String auth = "sandbox_.....";
void getButton() {
var htmlL = """<div id="checkout-message"></div>
<div id="dropin-container"></div>
<button id="submit-button">Submit payment</button>""";
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'payment-container',
(int viewId) => DivElement()
..appendHtml(htmlL)
..style.border = 'none');
print(HtmlElementView(
viewType: "dropin-container",
));
}
void setupDropin() {
print(auth);
var status = payment(auth);
print("Status: $status");
}
#override
void initState() {
getButton();
setupDropin();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
child: Column(
children: <Widget>[
SizedBox(
height: 100,
),
Container(
width: 500.0,
height: 300.0,
child: HtmlElementView(
viewType: "payment-container",
),
)
],
),
),
);
}
When I run this code, I see only the submit button in the screen. Got this error from web console,
"options.selector or options.container must reference a valid DOM node."
How can I integrate the Braintree payment into the flutter web?
or any other international payment gateway that works in flutter web.
Technical Disclaimer: flutter-web is in beta and I would not recommend it to be used with any payment service. This might lead to critical issues and not advisable.
The HtmlElementView widget adds all its elements into shadowdom which is not directly accessible for the global javascript context. Check this issue here in github.
The solution would be to pass the DivElement reference to the external js function. For e.g. in your case
Create the div element out side the build method and hold a reference, like in initSate
DivElement paymentDiv;
#override
initState(){
// always call before rest of the logic.
super.initState();
var htmlL = """<div id="checkout-message"></div>
<div id="dropin-container"></div>
<button id="submit-button">Submit payment</button>""";
paymentDiv= DivElement()
..appendHtml(htmlL)
..style.border = 'none');
// remaining logic
}
Then in your build/other method pass this element for the registerViewFactory method.
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'payment-container',
(int viewId) => paymentDiv;
Set you JS interop to accept dynamic parameter.
#JS()
external String payment(dynamic auth);
Rewrite you Javascript to directly work with this element reference. e.g
function payment(auth){
var button = auth;
// Remaining logic
}
I'm trying to configure Identity Server to work with Ionic 2. I'm a bit confused on how to configure the Redirect urls. For when I'm testing in the browser.
I'm in the process of updating and integrating an OIDC Cordova component.
The old component git hub is here:
https://github.com/markphillips100/oidc-cordova-demo
I've created a typescript provider and registered it with my app.module.ts
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import { Component } from '#angular/core';
import * as Oidc from "oidc-client";
import { Events } from 'ionic-angular';
import { environment } from "../rules/environments/environment";
export class UserInfo {
user: Oidc.User = null;
isAuthenticated: boolean = false;
}
#Injectable()
export class OidcClientProvider {
USERINFO_CHANGED_EVENT_NAME: string = ""
userManager: Oidc.UserManager;
settings: Oidc.UserManagerSettings;
userInfo: UserInfo = new UserInfo();
constructor(public events:Events) {
this.settings = {
//authority: "https://localhost:6666",
authority: environment.identityServerUrl,
client_id: environment.clientAuthorityId,
//This doesn't work
post_logout_redirect_uri: "http://localhost/oidc",
redirect_uri: "http://localhost/oidc",
response_type: "id_token token",
scope: "openid profile",
automaticSilentRenew: true,
filterProtocolClaims: true,
loadUserInfo: true,
//popupNavigator: new Oidc.CordovaPopupNavigator(),
//iframeNavigator: new Oidc.CordovaIFrameNavigator(),
}
this.initialize();
}
userInfoChanged(callback: Function) {
this.events.subscribe(this.USERINFO_CHANGED_EVENT_NAME, callback);
}
signinPopup(args?): Promise<Oidc.User> {
return this.userManager.signinPopup(args);
}
signoutPopup(args?) {
return this.userManager.signoutPopup(args);
}
protected initialize() {
if (this.settings == null) {
throw Error('OidcClientProvider required UserMangerSettings for initialization')
}
this.userManager = new Oidc.UserManager(this.settings);
this.registerEvents();
}
protected notifyUserInfoChangedEvent() {
this.events.publish(this.USERINFO_CHANGED_EVENT_NAME);
}
protected clearUser() {
this.userInfo.user = null;
this.userInfo.isAuthenticated = false;
this.notifyUserInfoChangedEvent();
}
protected addUser(user: Oidc.User) {
this.userInfo.user = user;
this.userInfo.isAuthenticated = true;
this.notifyUserInfoChangedEvent();
}
protected registerEvents() {
this.userManager.events.addUserLoaded(u => {
this.addUser(u);
});
this.userManager.events.addUserUnloaded(() => {
this.clearUser();
});
this.userManager.events.addAccessTokenExpired(() => {
this.clearUser();
});
this.userManager.events.addSilentRenewError(() => {
this.clearUser();
});
}
}
I'm trying to understand how I would configure the redirect urls so I can authenticate normally in the browser. Normally you would configure a redirect
url to take your process the token and claims after login.
this.settings = {
authority: environment.identityServerUrl,
client_id: environment.clientAuthorityId,
post_logout_redirect_uri: "http://localhost:8100/oidc",
redirect_uri: "http://localhost:8100/oidc",
response_type: "id_token token",
scope: "openid profile AstootApi",
automaticSilentRenew: true,
filterProtocolClaims: true,
loadUserInfo: true,
//popupNavigator: new Oidc.CordovaPopupNavigator(),
//iframeNavigator: new Oidc.CordovaIFrameNavigator(),
}
Ionic 2 doesn't use urls for routing, Supposing I have a component AuthenticationPage which handles storing the authentication token.
How can I configured a redirect url so it navigates to the authentication page, so I can test this in the browser?
TL;DR
I had to do a few things to get this working.
I didn't realize at first but My Redirect Urls had to be matching for what my client has stored in identity server.
new Client
{
ClientId = "myApp",
ClientName = "app client",
AccessTokenType = AccessTokenType.Jwt,
RedirectUris = { "http://localhost:8166/" },
PostLogoutRedirectUris = { "http://localhost:8166/" },
AllowedCorsOrigins = { "http://localhost:8166" },
//...
}
So the OIDC client in Typescript needed to be updated too.
this.settings = {
authority: environment.identityServerUrl,
client_id: environment.clientAuthorityId,
post_logout_redirect_uri: "http://localhost:8166/",
redirect_uri: "http://localhost:8166/",
response_type: "id_token token",
}
Also since I didn't feel like setting up routing in Ionic I needed to figure out a way to a url to communicate with Ionic (For Browser testing purpose, normal commucation will be done through cordova).
So I pointed the redirct url to be the url ionic is hosting my application and on app.Component.ts in the Constructor I added code to try to get my authentication token.
constructor(
public platform: Platform,
public menu: MenuController,
public oidcClient: OidcClientProvider
)
{
//Hack: since Ionic only has 1 default address, attempt to verify if this is a call back before calling
this.authManager.verifyLoginCallback().then((isSuccessful) => {
if (!isSuccessful) {
this.authManager.IsLoggedIn().then((isLoggedIn) => {
if (isLoggedIn) {
return;
}
this.nav.setRoot(LoginComponent)
});
}
});
}
Edit Verify login call back should just the oidc client call back which will read the token from the get params
verifyLoginCallback(): Promise<boolean> {
return this.oidcClient.userManager.signinPopupCallback()
.then(user => {
return this.loginSuccess(user).
then(() => true,
() => false);
}, err => { console.log(err); return false; });
}
NOTE the Login component is just a modal which represents login landing page, which just uses a login button to initialize the popup. You can hook this into any user driven event to trigger the login, but you must use a user driven event if you want to support the web without triggering a popup blocker
<ion-footer no-shadow>
<ion-toolbar no-shadow position="bottom">
<button ion-button block (click)="login()">Login</button>
</ion-toolbar>
</ion-footer>
login(): Promise<any> {
return this.oidcClient.signinPopup().then((user) => {
this.events.publish(environment.events.loginSuccess);
}).catch((e) => { console.log(e); });
}
I'm sure there is a better do the redirect to a different route, This is just a quick and dirty hack
I'm developing a web site using Angular 2.
Is there any way to disable or trigger Browser back button using Angular 2?
Thanks
Not sure if this is already sorted, but posting the answer nonetheless, for future references.
To tackle this, you basically need to add a listener in your app-component and setup a canDeactivate guard on your angular-router.
// in app.component.ts
import { LocationStrategy } from '#angular/common';
#Component({
selector: 'app-root'
})
export class AppComponent {
constructor(
private location: LocationStrategy
) {
// check if back or forward button is pressed.
this.location.onPopState(() => {
// set isBackButtonClicked to true.
this.someNavigationService.setBackClicked(true);
return false;
});
}
}
// in navigation guard
#Injectable()
export class NavigationGuard implements CanDeactivate<any> {
constructor(private someNavigationService: SomeNavigationService) {}
canDeactivate(component: any) {
// will prevent user from going back
if (this.someNavigationService.getBackClicked()) {
this.someNavigationService.setBackClicked(false);
// push current state again to prevent further attempts.
history.pushState(null, null, location.href);
return false;
}
return true;
}
}
import { LocationStrategy } from '#angular/common';
constructor( private location: LocationStrategy){
// preventing back button in browser implemented by "Samba Siva"
history.pushState(null, null, window.location.href);
this.location.onPopState(() => {
history.pushState(null, null, window.location.href);
});
}
its working fine to me 100% in angular2/4/5
This Very simple, use the following code, This example code is from plain javascript i have converted this into angular and using in my 2-3 projects
// Inject LocationStrategy Service into your component
constructor(
private locationStrategy: LocationStrategy
) { }
// Define a function to handle back button and use anywhere
preventBackButton() {
history.pushState(null, null, location.href);
this.locationStrategy.onPopState(() => {
history.pushState(null, null, location.href);
})
}
You can define preventBackButton in any service as well and call it from there
Snippet that I use and works across all major browsers!
ngOnInit() {
history.pushState(null, null, location.href);
this.subscription = fromEvent(window, 'popstate').subscribe(_ => {
history.pushState(null, null, location.href);
this.openModal(`You can't make changes or go back at this time.`, 'Okay');
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
I've tried all the solutions mentioned above but none of them worked perfectly for me. Finally I've found this npm module that worked immediately and perfectly, after two days of failed attempts.
Github: https://github.com/Zatikyan/angular-disable-browser-back-button#readme
A bit late perhaps but maybe somebody can use it.
This is a solution I use for a page with tabs (Bootstrap 4 style) where each tab is a component.
#Injectable()
export class CanNavigateService {
private static _isPermissionGranted = true
public navigationAttempt = new Subject<boolean>()
//-------------------------------------------------------------//
/**Will the next navigation attempt be permitted? */
updatePermission(isPermissionGranted: boolean) {
CanNavigateService._isPermissionGranted = isPermissionGranted
}//updatePermission
//-------------------------------------------------------------//
/**Broadcast the last attempt and whether it was permitted */
updateNavigationAttempt(wasPermissionGranted: boolean) {
this.navigationAttempt.next(wasPermissionGranted)
}//updatePermission
//-------------------------------------------------------------//
/**Can we navigate? */
public isPermissionGranted(): boolean {
return CanNavigateService._isPermissionGranted
}//isPermissionGranted
}//Cls
NavigationGuard like #Jithin Nair above but also broadcasts when an attempt to navigate was made and whether it was permitted. Subscribers of CanNavigateService can use it to decide what to do instead of back navigation.
#Injectable()
export class NavigationGuard implements CanDeactivate<any> {
constructor(private canNavigateService: CanNavigateService) { }
//--------------------------------------------------------------------//
// will prevent user from going back if permission has not been granted
canDeactivate(component: any) {
let permitted = this.canNavigateService.isPermissionGranted()
this.canNavigateService.updateNavigationAttempt(permitted)
if (!permitted) {
// push current state again to prevent further attempts.
history.pushState(null, null, location.href)
return false
}
return true
}//canDeactivate
}//Cls
Usage:
constructor(private _navigateService: CanNavigateService) {
super()
_navigateService.navigationAttempt.subscribe(wasPermitted => {
//If navigation was prevented then just go to first tab
if (!wasPermitted)
this.onTabSelected( this._firstTab)
})
}//ctor
//----------------------------------------------------------------------------//
onTabSelected(tab) {
this._selectedTab = tab
//If it's not the first tab you can't back navigate
this._navigateService.updatePermission(this._selectedTab == this._firstTab)
}//onTabSelected
try to use this
window.onpopstate = function (e) { window.history.forward(1); }
Try this
<script type = "text/javascript" >
history.pushState(null, null, 'pagename');
window.addEventListener('popstate', function(event) {
history.pushState(null, null, 'pagename');
});
</script>
where change 'pagename' to your page name and put this into head section of page.
If you want to prevent a route to be reached you can add the #CanActivate() decorator to your routing component
#Component({selector: 'control-panel-cmp', template: `<div>Settings: ...</div>`})
#CanActivate(checkIfWeHavePermission)
class ControlPanelCmp {
}
See also
- Angular 2: Inject a dependency into #CanActivate? for access to global services.
- Angular2 Router - Anyone know how to use canActivate in app.ts so that I can redirect to home page if not logged in
Why not use just this. Should avoid browser insert automatically things in the history. Just insert in some main.ts (or elsewhere executed at startup)
history.pushState = () => {};
Object.freeze(history);
This issue occurs on IE browser. Use below mentioned code it will resolve your issue.
#HostListener('document:keydown', ['$event'])
onKeyDown(evt: KeyboardEvent) {
if (
evt.keyCode === 8 || evt.which === 8
) {
let doPrevent = true;
const types =['text','password','file','search','email','number','date','color','datetime','datetime-local','month','range','search','tel','time','url','week'];
const target = (<HTMLInputElement>evt.target);
const disabled = target.disabled || (<HTMLInputElement>event.target).readOnly;
if (!disabled) {
if (target.isContentEditable) {
doPrevent = false;
} else if (target.nodeName === 'INPUT') {
let type = target.type;
if (type) {
type = type.toLowerCase();
}
if (types.indexOf(type) > -1) {
doPrevent = false;
}
} else if (target.nodeName === 'TEXTAREA') {
doPrevent = false;
}
}
if (doPrevent) {
evt.preventDefault();
return false;
}
}
}
If you are looking to disable browser back button in angular(7/8/9/10)... Try this link and install package using npm.
1) npm install --save angular-disable-browser-back-button
2) import { NgModule } from '#angular/core';
import { BackButtonDisableModule } from 'angular-disable-browser-back-button';
#NgModule({
...
imports: [
...
BackButtonDisableModule.forRoot()
],
...
})
export class AppModule {}
3) BackButtonDisableModule.forRoot({
preserveScrollPosition: true
})
Please use this link given below.. reference taken from.
[https://www.npmjs.com/package/angular-disable-browser-back-button][1]
This isn't Angular2 related problem. You can send the user back in history. See Manipulating the browser history, history.go() method particular:
window.history.go(-1);
However, I don't think there's a way to cancel or disable default browser action on pressing back button in the browser window because that could be very easily abused.
As an alternative you can show a dialog window when user tries to leave the page: javascript before leaving the page
Add following code in TS file of the component, where you don't want to go back.
#HostListener('window:hashchange', ['$event'])
hashChangeHandler(e) {
window.location.hash = "dontgoback";
}
step 1: Import Locatoion from angular commmon
import {Location} from "#angular/common";
step 2: Initialise in constructor
private location: Location
step 3: Add function in ngOnInit of the respective coponent,
this.location.subscribe(currentLocation => {
if (currentLocation.url === '*/basic-info*') {
window.onpopstate = function (event) {
history.go(1);
}
}
});
Note: Here /basic-info will be replaced by your path.
If first time it is not working, try adding outside subscribe,
let currentUrl = window.location.href;
let tmpVar = currentUrl.includes('/basic-info');
if (currentUrl.includes('/basic-info')) {
window.onpopstate = function (event) {
history.go(1);
}
}