I created a page with an iframe. The url that the iframe will render has some input fields. When I type something, it reload all the page and I can do nothing.
View
<ion-content no-padding>
<iframe [src]="urlpaste()"></iframe>
</ion-content>
Controller
import { Component } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
my_url: any;
constructor(private sanitize: DomSanitizer) {}
urlpaste(){
this.my_url = "http://example.com/";
return this.sanitize.bypassSecurityTrustResourceUrl(this.my_url);
}
}
It looks like this may have to do with the resize event(s) generated from clicking into the input field, in which case a zoom in happens or the on-screen keyboard pushes the form up. See this:
Ionic 2 Form goes up when keyboard shows
Related
I am trying to implement a feature similar to whats available in Facebook i.e. if you have scrolled the news feed, pressing hardware back button takes you to the top of the list.
For this I think believe canDeactivate of Router Guards would be the proper ways.
But I am unable to find a way to check if the page has been scrolled or not.
I have tried window.pageYOffset but this always returns 0, accessing ViewChild within a Guard always returns null.
Can anyone please guide how to achieve this?
There are two approaches for this that should help you.
First, starting with Ionic 4, you can register you back button handler using the Platform features:
https://www.freakyjolly.com/ionic-4-overridden-back-press-event-and-show-exit-confirm-on-application-close/
this.platform.backButton.subscribeWithPriority(999990, () => {
//alert("back pressed");
});
Secondly, you can use more features of Ionic 4 called scrollEvents.
I have explained how to use this feature in other answers:
How to detect if ion-content has a scrollbar?
How to detect scroll reached end in ion-content component of Ionic 4?
ionic 4 - scroll to an x,y coordinate on my webView using typeScript
Hopefully that will get you moving in the right direction.
I think that last answer should solve most of your issue, so something like this:
Freaky Jolly has a tutorial explaining how to scroll to an X/Y coord.
First, you need scrollEvents on the ion-content:
<ion-header>
<ion-toolbar>
<ion-title>
Ion Content Scroll
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [scrollEvents]="true">
<!-- your content in here -->
</ion-content>
In the code you need to use a #ViewChild to get a code reference to the ion-content then you can use its ScrollToPoint() api:
import { Component, ViewChild } from '#angular/core';
import { Platform, IonContent } from '#ionic/angular';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
// This property will save the callback which we can unsubscribe when we leave this view
public unsubscribeBackEvent: any;
#ViewChild(IonContent) content: IonContent;
constructor(
private platform: Platform
) { }
//Called when view is loaded as ionViewDidLoad() removed from Ionic v4
ngOnInit(){
this.initializeBackButtonCustomHandler();
}
//Called when view is left
ionViewWillLeave() {
// Unregister the custom back button action for this page
this.unsubscribeBackEvent && this.unsubscribeBackEvent();
}
initializeBackButtonCustomHandler(): void {
this.unsubscribeBackEvent = this.platform.backButton.subscribeWithPriority(999999, () => {
this.content.scrollToPoint(0,0,1500);
});
/* here priority 101 will be greater then 100
if we have registerBackButtonAction in app.component.ts */
}
}
I have two ngx-bootstrap modals created as a standalone components (not with template variables) - Login modal and Register modal. Each of the modals are have separate components which are located in my shared module and can be called from other modules. But the thing is that there is an option these modals to call each other - you can click a button from the login modal which has to bring you the Register modal and vice versa. When I try doing this using the BsModalService I get circular dependency errors since I have imported the login component in the register component and the register component in the login component.
I've tried to put this modal switching logic in a service with the hope that I won't get a circular dependency but it didn't help.
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
import { UserService } from 'src/app/core/services';
import { User } from 'src/app/core';
import { RegisterModalComponent } from '../register-modal/register-modal.component';
#Component({
selector: 'app-login-modal',
templateUrl: './login-modal.component.html',
styleUrls: ['./login-modal.component.css']
})
export class LoginModalComponent implements OnInit {
loginForm: FormGroup = this.fb.group({
// form definition
});
constructor(
public loginModalRef: BsModalRef,
private fb: FormBuilder,
private router: Router,
private user: UserService,
private modalService: BsModalService
) { }
ngOnInit() {
}
onSubmit() {
// form submit code ...
// hide the current modal
this.loginModalRef.hide();
}
openRegisterModal() {
// hide the current modal
this.loginModalRef.hide();
// open the new modal
this.modalService.show(RegisterModalComponent, {
animated: true,
class: 'modal-lg'
});
}
}
I have included only the code from the login modal since the situation on the other side is similar.
Just to mention that as a temporary solution I just made one modal component to serve the purpose as modal and I refactored the login and the register components to be like a regular components so I can include them inside the modal and switch them with ngIf depending on the parameters that I'm calling the modal with.
I'm working on Ionic App, I want to hide navbar and tabs on scroll down and show them on scroll up.
Anyone know how to do this? Please help.
Thanks in advance.
a very naive implementation would be:
add a var that will be your boolean flag for state (shown/hidden)
add change detector ref into your component (as you will need to cdr
change of this boolean to propagate UI)
bind your header/footer via *ngIf directive
Something like this:
import { Component, ChangeDetectorRef } from '#angular/core';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage2 {
headerVisible: boolean = false;
constructor(
public cdr: ChangeDetectorRef
) {
}
scrollState(event) {
if (event.directionY == "up") {
this.headerVisible = false;
} else {
this.headerVisible = true;
}
this.cdr.detectChanges();
}
}
And in your template:
<ion-header *ngIf="headerVisible">
<ion-navbar>
<ion-title>
Ionic Blank
</ion-title>
</ion-navbar>
</ion-header>
But most probably instead of *ngIf you would want to alter header's/footer's height so that your overall template dealt better with margins.
Also please note that ideally you don't want scroll event to "spam" so you need to implement proper way you capture the state (up or down) without it (debounce / throttle it)
We am using ionic 3 with d3js. We have lot of d3.js transitions in each component (which we believe takes lot of memory).
App responds quickly(fast) to navigation and content rendering initially however after navigating 5-10 pages, app gets slower. We see lag in page navigations and content rendering.
We believe this is because of view caching in iconic 3 (not sure if view caching is enabled in iconic 3).
When user clicks on navigation buttons, we push or pop from NavController.
Is there way to disable view caching so that app performance is same irrespective of how many times user navigates between views?
"#ionic/app-scripts": "3.1.9",
"#ionic-native/core": "4.7.0",
Sample code between home page and graph page.
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController) {
console.log('construct again');
}
showMigrationChart() {
this.navCtrl.push(MigrationChart);
}
showColumnChart() {
this.navCtrl.push(ColumnChart);
}
}
#Component({
selector: 'migration-chart',
templateUrl: '../../common/chart.html'
})
export class MigrationChart implements OnInit {
#ViewChild('appChart') private chartContainer: ElementRef;
public chartName = 'Column Chart';
constructor(public navCtrl: NavController) {
console.log('MigrationChart construct again');
}
ngOnInit() {
this.chartName = migrationEngine(this.chartContainer.nativeElement);
}
public onBackClick() {
console.log('getViews length= '+ this.navCtrl.length());
console.log('getViews = ', this.navCtrl.getViews());
this.navCtrl.pop();
}
}
There is no issue with Ionic framework.
On closing of page/component, there were no proper clean up of javascript timers and while loop which was causing app to slow down.
We changed code to do cleanup inside ngOnDestroy and everything work fine now.
I am building a mobile app and I'd like the user to have the ability to set their starting page via a settings-page. The idea is that the user can select a page from a list of options, the setting gets stored to local-storage and later, when the user logs back in, the user is automatically taken to that page first.
I have a page-service which contains a mapping of Id's to page-components. This is what I use to find the page I want to use when I read in my user's saved start-page data.
My issue is that I have developed a cyclic-dependency that I don't think I can break without finding a way to route in Ionic2 that doesn't involve using the injected component. As far as I can tell, the only way routing is achieved in Ionic2 is with the NavController.push(component) or Nav.setRoot(component).
PageService.ts
import {Injectable} from "#angular/core";
import {HomePage} from "../pages/home/home";
import {SettingsPage} from "../pages/settings/settings";
import {CartPage} from "../pages/cart/cart";
#Injectable()
export class PageService {
public pages = [
{
id: "HOME",
component: HomePage
}, {
id: "SETTINGS",
component: SettingsPage
}, {
id: "CART",
component: CartPage
}
];
constructor() {
}
getPageById(id: string) {
return this.pages.find(page => (page.id === id));
}
}
settings.ts:
My SettingsPage component has the PageService injected so that it can get access to get the list of pages. This is where my cyclical dependency occurs. The SettingsPage is injecting PageService which has a reference to SettingsPage in it.
import {Component} from "#angular/core";
import {PageService} from "../../providers/page-service";
import {UserService} from "../../providers/user-service";
#Component({
selector: "page-settings",
templateUrl: "settings.html",
})
export class SettingsPage {
startPages = [];
constructor(private pageService: PageService, private userService: UserService) {
this.startPages = this.pageService.getStartPages();
}
}
settings.html:
Just a simple list with a card to output the selection.
<ion-content padding>
<ion-list>
<ion-card padding>
<ion-card-title>Starting Page</ion-card-title>
<ion-item>
<ion-select [(ngModel)]="userService.activeUser.startPage">
<ion-option *ngFor="let page of startPages" value="{{page.id}}">
{{page.id}}
</ion-option>
</ion-select>
</ion-item>
</ion-card>
</ion-list>
</ion-content>
...and finally, when the app starts up and I want to automatically go to my start page I execute the following:
const startPage = this.pageService.getPageById(this.userService.activeUser.startPage);
this.nav.setRoot(startPage.component);
Updated answer
Use forward ref in the SettingsPage constructor..
constructor(#Inject(forwardRef(() => PageService)) private pageService: PageService) {
this.startPages = this.pageService.getStartPages();
}
Old Answer - not appropriate because angular should be handling the instantiation of services through injection. "new"ing is a bad idea (but it did work).
I changed how the PageService was loaded in the SettingsPage and the cyclical dependency was resolved. I moved the PageService code out of the constructor and put it into the ngAfterViewInit() function. Now the PageService is only instantiated when the view is loaded.
ngAfterViewInit(){
this.pageService = new PageService();
this.startPages = this.pageService.getStartPages();
}