fix(angular): change detection

This commit is contained in:
Manu Mtz.-Almeida
2018-04-06 16:19:32 +02:00
parent a3cd5db3a7
commit 79ba6391d6
6 changed files with 60 additions and 51 deletions

View File

@ -1,7 +1,7 @@
import { Directive, ElementRef, HostListener, Input, Optional } from '@angular/core'; import { Directive, ElementRef, HostListener, Input, Optional } from '@angular/core';
import { IonRouterOutlet } from './ion-router-outlet';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { NavController } from '../..'; import { NavController } from '../../providers/nav-controller';
import { IonRouterOutlet } from './ion-router-outlet';
@Directive({ @Directive({
selector: 'ion-back-button' selector: 'ion-back-button'

View File

@ -2,7 +2,7 @@
import { Directive as NgDirective, ElementRef, EventEmitter as NgEventEmitter, Input as NgInput, Output as NgOutput } from '@angular/core'; import { Directive as NgDirective, ElementRef, EventEmitter as NgEventEmitter, Input as NgInput, Output as NgOutput } from '@angular/core';
export function method(ref: ElementRef, methodName: string, ...args: any[]) { export function method(ref: ElementRef, methodName: string, args: any[]) {
return ref.nativeElement.componentOnReady() return ref.nativeElement.componentOnReady()
.then((el: any) => el[methodName].apply(el, args)); .then((el: any) => el[methodName].apply(el, args));
} }
@ -907,8 +907,6 @@ export class Menu {
@NgInput() maxEdgeStart: number; @NgInput() maxEdgeStart: number;
@NgOutput() ionOpen: NgEventEmitter<any>; @NgOutput() ionOpen: NgEventEmitter<any>;
@NgOutput() ionClose: NgEventEmitter<any>; @NgOutput() ionClose: NgEventEmitter<any>;
@NgOutput() ionMenuDidLoad: NgEventEmitter<any>;
@NgOutput() ionMenuDidUnload: NgEventEmitter<any>;
@NgOutput() ionMenuChange: NgEventEmitter<any>; @NgOutput() ionMenuChange: NgEventEmitter<any>;
isOpen(...__args: any[]): Promise<any> { isOpen(...__args: any[]): Promise<any> {
return method(this.r, isOpen, __args); return method(this.r, isOpen, __args);

View File

@ -1,10 +1,4 @@
import { import { ApplicationRef, ComponentFactoryResolver, Injectable, Injector, NgZone } from '@angular/core';
ApplicationRef,
ComponentFactoryResolver,
Injectable,
Injector,
} from '@angular/core';
import { FrameworkDelegate, ViewLifecycle } from '@ionic/core'; import { FrameworkDelegate, ViewLifecycle } from '@ionic/core';
@ -12,11 +6,12 @@ import { FrameworkDelegate, ViewLifecycle } from '@ionic/core';
export class AngularDelegate { export class AngularDelegate {
constructor( constructor(
private appRef: ApplicationRef private appRef: ApplicationRef,
private zone: NgZone
) {} ) {}
create(cfr: ComponentFactoryResolver, injector: Injector) { create(cfr: ComponentFactoryResolver, injector: Injector) {
return new AngularFrameworkDelegate(cfr, injector, this.appRef); return new AngularFrameworkDelegate(cfr, injector, this.appRef, this.zone);
} }
} }
@ -28,40 +23,61 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
constructor( constructor(
private cfr: ComponentFactoryResolver, private cfr: ComponentFactoryResolver,
private injector: Injector, private injector: Injector,
private appRef: ApplicationRef private appRef: ApplicationRef,
private zone: NgZone,
) {} ) {}
attachViewToDom(container: any, component: any, data?: any, cssClasses?: string[]): Promise<any> { attachViewToDom(container: any, component: any, params?: any, cssClasses?: string[]): Promise<any> {
return new Promise(resolve => {
const componentFactory = this.cfr.resolveComponentFactory(component); this.zone.run(() => {
const hostElement = document.createElement(componentFactory.selector); const el = attachView(
if (data) { this.cfr, this.injector, this.appRef, this.elRefMap,
Object.assign(hostElement, data); container, component, params, cssClasses
} );
resolve(el);
const childInjector = Injector.create([], this.injector); });
const componentRef = componentFactory.create(childInjector, [], hostElement); });
for (const clazz of cssClasses) {
hostElement.classList.add(clazz);
}
bindLifecycleEvents(componentRef.instance, hostElement);
container.appendChild(hostElement);
this.appRef.attachView(componentRef.hostView);
this.elRefMap.set(hostElement, componentRef);
return Promise.resolve(hostElement);
} }
removeViewFromDom(_container: any, component: any): Promise<void> { removeViewFromDom(_container: any, component: any): Promise<void> {
const componentRef = this.elRefMap.get(component); return new Promise(resolve => {
if (componentRef) { this.zone.run(() => {
componentRef.destroy(); const componentRef = this.elRefMap.get(component);
this.elRefMap.delete(component); if (componentRef) {
} componentRef.destroy();
return Promise.resolve(); this.elRefMap.delete(component);
}
resolve();
});
});
} }
} }
export function attachView(
cfr: ComponentFactoryResolver,
injector: Injector,
appRef: ApplicationRef,
elRefMap: WeakMap<HTMLElement, any>,
container: any, component: any, data?: any, cssClasses?: string[]) {
const componentFactory = cfr.resolveComponentFactory(component);
const hostElement = document.createElement(componentFactory.selector);
if (data) {
Object.assign(hostElement, data);
}
const childInjector = Injector.create([], injector);
const componentRef = componentFactory.create(childInjector, [], hostElement);
for (const clazz of cssClasses) {
hostElement.classList.add(clazz);
}
bindLifecycleEvents(componentRef.instance, hostElement);
container.appendChild(hostElement);
appRef.attachView(componentRef.hostView);
elRefMap.set(hostElement, componentRef);
return hostElement;
}
const LIFECYCLES = [ const LIFECYCLES = [
ViewLifecycle.WillEnter, ViewLifecycle.WillEnter,
ViewLifecycle.DidEnter, ViewLifecycle.DidEnter,

View File

@ -1,6 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { PageTwo } from './page-two'; import { PageTwo } from './page-two';
import { Nav } from '@ionic/angular';
@Component({ @Component({
selector: 'page-one', selector: 'page-one',
@ -29,9 +30,7 @@ export class PageOne {
ionViewWillEnterDetection = 'initial'; ionViewWillEnterDetection = 'initial';
ionViewDidEnterDetection = 'initial'; ionViewDidEnterDetection = 'initial';
constructor() { constructor(private nav: Nav) {}
}
ngOnInit() { ngOnInit() {
@ -55,8 +54,7 @@ export class PageOne {
}, 500); }, 500);
} }
goToPageTwo() { async goToPageTwo() {
const nav = document.querySelector('ion-nav') as any; await this.nav.push(PageTwo);
nav.push(PageTwo).then(() => console.log('push complete'));
} }
} }

View File

@ -1,12 +1,10 @@
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core'; import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
import { Animation, AnimationBuilder, Config, CssClassMap } from '../../index'; import { Animation, AnimationBuilder, Config, CssClassMap } from '../../index';
import { createThemedClasses, getClassMap } from '../../utils/theme';
import { BACKDROP, OverlayEventDetail, OverlayInterface, dismiss, eventMethod, isCancel, present } from '../../utils/overlays'; import { BACKDROP, OverlayEventDetail, OverlayInterface, dismiss, eventMethod, isCancel, present } from '../../utils/overlays';
import { createThemedClasses, getClassMap } from '../../utils/theme';
import iosEnterAnimation from './animations/ios.enter'; import iosEnterAnimation from './animations/ios.enter';
import iosLeaveAnimation from './animations/ios.leave'; import iosLeaveAnimation from './animations/ios.leave';
import mdEnterAnimation from './animations/md.enter'; import mdEnterAnimation from './animations/md.enter';
import mdLeaveAnimation from './animations/md.leave'; import mdLeaveAnimation from './animations/md.leave';

View File

@ -1,11 +1,10 @@
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core'; import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
import { Animation, AnimationBuilder, Config, CssClassMap } from '../../index'; import { Animation, AnimationBuilder, Config, CssClassMap } from '../../index';
import { createThemedClasses, getClassMap } from '../../utils/theme';
import { BACKDROP, OverlayEventDetail, OverlayInterface, dismiss, eventMethod, isCancel, present } from '../../utils/overlays'; import { BACKDROP, OverlayEventDetail, OverlayInterface, dismiss, eventMethod, isCancel, present } from '../../utils/overlays';
import { createThemedClasses, getClassMap } from '../../utils/theme';
import iosEnterAnimation from './animations/ios.enter'; import iosEnterAnimation from './animations/ios.enter';
import iosLeaveAnimation from './animations/ios.leave'; import iosLeaveAnimation from './animations/ios.leave';
import mdEnterAnimation from './animations/md.enter'; import mdEnterAnimation from './animations/md.enter';
import mdLeaveAnimation from './animations/md.leave'; import mdLeaveAnimation from './animations/md.leave';