diff --git a/packages/angular/src/providers/angular-component-mounter.ts b/packages/angular/src/providers/angular-component-mounter.ts index 1a661d91bb..8b2de049c1 100644 --- a/packages/angular/src/providers/angular-component-mounter.ts +++ b/packages/angular/src/providers/angular-component-mounter.ts @@ -1,7 +1,6 @@ import { ApplicationRef, ComponentFactoryResolver, - ComponentRef, Injectable, Injector, NgZone, @@ -12,7 +11,7 @@ import { import { getProviders } from '../di/di'; import { AngularMountingData } from '../types/interfaces'; -const elementToComponentRefMap = new Map>(); +const elementToComponentRefMap = new Map(); @Injectable() export class AngularComponentMounter { @@ -20,14 +19,14 @@ export class AngularComponentMounter { constructor(private defaultCfr: ComponentFactoryResolver, private zone: NgZone, private appRef: ApplicationRef) { } - attachViewToDom(parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type, componentResolveFactory: ComponentFactoryResolver, injector: Injector, data: any, classesToAdd: string[], wrapUserTemplateInIonPage: boolean): Promise { + attachViewToDom(parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type, componentResolveFactory: ComponentFactoryResolver, injector: Injector, data: any, classesToAdd: string[], wrapUserComponentInIonPage: boolean): Promise { return new Promise((resolve) => { this.zone.run(() => { const crf = componentResolveFactory ? componentResolveFactory : this.defaultCfr; - const mountingData = attachViewToDom(crf, parentElement, hostElement, componentToMount, injector, this.appRef, data, classesToAdd, wrapUserTemplateInIonPage); + const mountingData = attachViewToDom(crf, parentElement, hostElement, componentToMount, injector, this.appRef, data, classesToAdd, wrapUserComponentInIonPage); resolve(mountingData); }); }); @@ -45,16 +44,17 @@ export class AngularComponentMounter { } export function removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement) { - const componentRef = elementToComponentRefMap.get(childElement); - if (componentRef) { - componentRef.destroy(); - if (parentElement.contains(childElement)) { - parentElement.removeChild(childElement); + const mountingData = elementToComponentRefMap.get(childElement); + if (mountingData) { + const componentParent = mountingData.element.parentNode; + mountingData.componentRef.destroy(); + if (mountingData.wrapUserComponentInIonPage && parentElement.contains(componentParent) ) { + parentElement.removeChild(componentParent) } } } -export function attachViewToDom(crf: ComponentFactoryResolver, parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type, injector: Injector, appRef: ApplicationRef, data: any, classesToAdd: string[], wrapUserTemplateInIonPage: boolean): AngularMountingData { +export function attachViewToDom(crf: ComponentFactoryResolver, parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type, injector: Injector, appRef: ApplicationRef, data: any, classesToAdd: string[], wrapUserComponentInIonPage: boolean): AngularMountingData { const componentProviders = ReflectiveInjector.resolve(getProviders(parentElement, data)); const componentFactory = crf.resolveComponentFactory(componentToMount); @@ -62,32 +62,34 @@ export function attachViewToDom(crf: ComponentFactoryResolver, parentElement: HT hostElement = document.createElement(componentFactory.selector); } - let mountingElement = hostElement; - if (wrapUserTemplateInIonPage) { - const ionPageElement = document.createElement('ion-page'); - hostElement.appendChild(ionPageElement); - mountingElement = ionPageElement; - } - const childInjector = ReflectiveInjector.fromResolvedProviders(componentProviders, injector); - const componentRef = componentFactory.create(childInjector, [], mountingElement); + const componentRef = componentFactory.create(childInjector, [], hostElement); for (const clazz of classesToAdd) { hostElement.classList.add(clazz); } - parentElement.appendChild(hostElement); + const elementToAppend = wrapUserComponentInIonPage ? getIonPageElement(hostElement) : hostElement; + parentElement.appendChild(elementToAppend); appRef.attachView(componentRef.hostView); - elementToComponentRefMap.set(hostElement, componentRef); - - return { + const mountingData = { componentFactory, childInjector, componentRef, instance: componentRef.instance, angularHostElement: componentRef.location.nativeElement, element: hostElement, + wrapUserComponentInIonPage }; + + elementToComponentRefMap.set(hostElement, mountingData); + + return mountingData; } +export function getIonPageElement(hostElement: HTMLElement) { + const page = document.createElement('ion-page'); + page.appendChild(hostElement); + return page; +} \ No newline at end of file diff --git a/packages/angular/src/types/interfaces.ts b/packages/angular/src/types/interfaces.ts index 1b4d4acfaa..afb521b01c 100644 --- a/packages/angular/src/types/interfaces.ts +++ b/packages/angular/src/types/interfaces.ts @@ -12,4 +12,5 @@ export interface AngularMountingData extends FrameworkMountingData { componentRef?: ComponentRef; instance?: any; angularHostElement?: HTMLElement; + wrapUserComponentInIonPage?: boolean; } diff --git a/packages/core/src/utils/dom-framework-delegate.ts b/packages/core/src/utils/dom-framework-delegate.ts index fb68411cfe..b15c2c6d02 100644 --- a/packages/core/src/utils/dom-framework-delegate.ts +++ b/packages/core/src/utils/dom-framework-delegate.ts @@ -1,21 +1,24 @@ import { FrameworkDelegate, FrameworkMountingData, } from '../index'; -import { isString } from './helpers'; +import { isElementModal, isElementNav, isString } from './helpers'; export class DomFrameworkDelegate implements FrameworkDelegate { attachViewToDom(parentElement: HTMLElement, tagOrElement: string | HTMLElement, propsOrDataObj: any = {}, classesToAdd: string[] = []): Promise { return new Promise((resolve) => { const usersElement = (isString(tagOrElement) ? document.createElement(tagOrElement) : tagOrElement) as HTMLElement; - Object.assign(usersElement, propsOrDataObj); + if (classesToAdd.length) { for (const clazz of classesToAdd) { usersElement.classList.add(clazz); } } - parentElement.appendChild(usersElement); + + const elementToAppend = shouldWrapInIonPage(parentElement) ? createIonPageAndAppendUserElement(usersElement) : usersElement; + parentElement.appendChild(elementToAppend); + resolve({ - element: usersElement + element: elementToAppend }); }); } @@ -27,3 +30,13 @@ export class DomFrameworkDelegate implements FrameworkDelegate { }); } } + +export function shouldWrapInIonPage(element: HTMLElement) { + return isElementModal(element) || isElementNav(element); +} + +export function createIonPageAndAppendUserElement(userElement: HTMLElement) { + const wrappingElement = document.createElement('ion-page'); + wrappingElement.appendChild(userElement); + return wrappingElement; +} diff --git a/packages/core/src/utils/helpers.ts b/packages/core/src/utils/helpers.ts index 42bf31f1c8..bd4a2e3193 100644 --- a/packages/core/src/utils/helpers.ts +++ b/packages/core/src/utils/helpers.ts @@ -24,6 +24,14 @@ export function isStringOrNumber(v: any): v is (string | number) { return isStri export function isBlank(val: any): val is null { return val === undefined || val === null; } +export function isElementNav(element: HTMLElement) { + return element.tagName.toUpperCase() === 'ION-NAV'; +} + +export function isElementModal(element: HTMLElement) { + return element.classList.contains('modal-wrapper'); +} + /** @hidden */ export function isCheckedProperty(a: any, b: any): boolean { if (a === undefined || a === null || a === '') { diff --git a/packages/react/src/react-framework-delegate.ts b/packages/react/src/react-framework-delegate.ts index 1ad2293dda..2ae8bb81e6 100644 --- a/packages/react/src/react-framework-delegate.ts +++ b/packages/react/src/react-framework-delegate.ts @@ -2,10 +2,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { FrameworkDelegate } from '@ionic/core'; +import { isElementModal, isElementNav } from './utils/helpers'; export function attachViewToDom(parentElement: HTMLElement, reactComponent: any, propsOrData: any, classesToAdd: string[]) { - console.log('parentElement: ', parentElement); - console.log('reactComponent: ', reactComponent); const wrappingDiv = shouldWrapInIonPage(parentElement) ? document.createElement('ion-page') : document.createElement('div'); if (classesToAdd) { for (const clazz of classesToAdd) { @@ -41,8 +40,5 @@ export { Delegate } export function shouldWrapInIonPage(element: HTMLElement) { - if (element.tagName.toUpperCase() === 'ION-NAV' || element.classList.contains('modal-wrapper')) { - return true; - } - return false; -} \ No newline at end of file + return isElementModal(element) || isElementNav(element); +} diff --git a/packages/react/src/utils/helpers.ts b/packages/react/src/utils/helpers.ts index 01b0c1ced7..b9a696f13a 100644 --- a/packages/react/src/utils/helpers.ts +++ b/packages/react/src/utils/helpers.ts @@ -7,4 +7,12 @@ export function getOrAppendElement(tagName: string): Element { const tmp = document.createElement(tagName); document.body.appendChild(tmp); return tmp; -} \ No newline at end of file +} + +export function isElementNav(element: HTMLElement) { + return element.tagName.toUpperCase() === 'ION-NAV'; +} + +export function isElementModal(element: HTMLElement) { + return element.classList.contains('modal-wrapper'); +}