How to open a modal component from inside of another modal component without having a circular dependency? - modal-dialog

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.

Related

Detect a click outside of an element

There is some components in Ionic that do not provide an event that is emitted when focus is lost.
For example ion-input provides ionBlur. On the other hand there is other elements like ion-content where I need to detect an outside click, but without knowing which event to use.
Is there a way to achieve that without being limited to the proposed events in the documentation?
I found this article that shows a way to use a custom directive to detect an outside click:
import {Directive, ElementRef, Output, EventEmitter, HostListener} from '#angular/core';
#Directive({
selector: '[clickOutside]'
})
export class ClickOutsideDirective {
constructor(private _elementRef : ElementRef) {
}
#Output()
public clickOutside = new EventEmitter();
#HostListener('document:click', ['$event.target'])
public onClick(targetElement) {
const clickedInside = this._elementRef.nativeElement.contains(targetElement);
if (!clickedInside) {
this.clickOutside.emit(null);
}
}
}
The directive can then be used this way, after declaring it in the concerned module:
<!-- HTML Template -->
<ion-content (clickOutside)="handleOutsideClick()"><!-- ... --></ion-content>
<!-- Typescript code -->
handleOutsideClick() {
//Handle My outside Click
}
Yeah, It's been 7 months since asked.
Stucked with the same issue; this solved the issue
TS
#ViewChild('content') content: ElementRef
#HostListener('document:click', ['$event'])
andClickEvent(event) {
if (!this.content.nativeElement.contains(event.target)) {
if (!this.navCtrl.isTransitioning() && this.navCtrl.getActive()) {
this.close()
}
}
}
HTML
<ion-content #content>

Ionic Iframe continuesly reload while typing

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

How to disable view caching in ionic 3

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.

Ionic 3+: how to navigate away from tabbed interface?

My Ionic application first loads LoginComponent and when user successfully logs in, loads the main TabsComponent view which allows to switch between corresponding child views.
I am trying to make it load standalone LoginComponent without tabbed interface, and that is not working (once switched to TabsComponent, I cannot navigate away from tabbed interface).
I've tried following commands from under one of TabsComponent child views:
this.navCtrl.push(LoginComponent); // Loads as a child view
this.navCtrl.setRoot(LoginComponent); // Loads as a child view
this.navCtrl.popAll(); // Error: navigation stack needs at least one root page
this.navCtrl.popTo(LoginComponent); // Error: navigation stack needs at least one root page
I've went through Ionic documentation many times but I haven't found an answer to this question. What am I missing?
I've solved this by injecting TabsComponent into it's child component, and then calling this.navCtrl.setRoot(LoginComponent); in a function inside TabsComponent:
// Child class of TabsComponent (loaded via tab click)
export class SettingsComponent {
constructor(#Inject(forwardRef(() => TabsComponent)) private tabsComponent: TabsComponent) {
}
logOut(): void {
this.tabsComponent.switchToLoginPage():
}
}
And switchToLoginPage on TabsComponent:
import {Component, forwardRef, Inject} from '#angular/core';
// ...
export class TabsComponent {
constructor(private navCtrl: NavController) {
}
switchToLoginPage(): void {
this.navCtrl.setRoot(LoginComponent);
}
}
Based on this example: How do I inject a parent component into a child component?
If there is a better way I'd love to know about, otherwise hope this solution would help anyone.

angular2 submit form in typescript

I need to submit a form coming from a payment gateway. Our backend guy asks me to either put the innerHtml and send after it rendered. I got it to work on Chrome, but failed on Firefox.
Now I'm trying to fix it on our testing environment, the backend added a JSON return of all the properties I need to replicate the form he was sending me so I can make my own form. But still failing to submit on Firefox.
Does someone have the same experience? Please shed me some light.
Is there any Firefox specific fixes I need to know?
Below is the working code on Chrome and Safari
import { Component, OnInit, AfterViewInit, ViewChild, ElementRef,DoCheck, ViewChildren, QueryList } from '#angular/core';
import { BrowserModule, DomSanitizer, SafeResourceUrl, SafeUrl} from '#angular/platform-browser';
import { PaymentService } from '../../_services/payment.service';
import { Loader } from '../../_services/loader.service';
#Component({
selector: 'bdf-payment-form',
templateUrl: './payment-form.component.html',
styleUrls: ['./payment-form.component.scss']
})
export class PaymentFormComponent implements OnInit,DoCheck, AfterViewInit {
form : SafeResourceUrl;
// #ViewChild('paymentFormContainer') container: ElementRef;
#ViewChild('paymentForm') myForm: ElementRef;
loader;
constructor(private paymentService:PaymentService,
private sanitizer: DomSanitizer,
private loaderService: Loader,
private elRef:ElementRef) { }
ngDoCheck(){
}
ngOnInit() {
console.log(this.paymentService.paymentForm);
this.paymentService.paymentForm ? this.form = this.sanitizer.bypassSecurityTrustHtml(this.paymentService.paymentForm) : null
this.loader = true;
}
ngAfterViewInit() {
let test;
if(this.form){
test = this.elRef.nativeElement.querySelector('form')
console.log(test)
test.submit();
}
}
}
You shouldn't use submit() method to avoid redirection with page refresh.
The http service is used to submit the form data serialized to json from the form. If you have form elements bound to the model then it would be easier to send the model back to the backend.