MOBILE-2338 compile: Monitor jsData changes

main
Dani Palou 2018-05-22 13:31:52 +02:00 committed by Pau Ferrer Ocaña
parent c626bee407
commit d53a7acda5
3 changed files with 70 additions and 34 deletions

View File

@ -18,6 +18,7 @@ import {
} from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
/**
* Component to create another component dynamically.
@ -68,7 +69,9 @@ export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck {
protected differ: any; // To detect changes in the data input.
constructor(logger: CoreLoggerProvider, protected factoryResolver: ComponentFactoryResolver, differs: KeyValueDiffers,
@Optional() protected navCtrl: NavController, protected cdr: ChangeDetectorRef, protected element: ElementRef) {
@Optional() protected navCtrl: NavController, protected cdr: ChangeDetectorRef, protected element: ElementRef,
protected domUtils: CoreDomUtilsProvider) {
this.logger = logger.getInstance('CoreDynamicComponent');
this.differ = differs.find([]).create();
}
@ -99,7 +102,7 @@ export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck {
if (changes) {
this.setInputData();
if (this.instance.ngOnChanges) {
this.instance.ngOnChanges(this.createChangesForComponent(changes));
this.instance.ngOnChanges(this.domUtils.createChangesFromKeyValueDiff(changes));
}
}
}
@ -170,29 +173,4 @@ export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck {
this.instance[name] = this.data[name];
}
}
/**
* Given the changes on the data input, create the changes object for the component.
*
* @param {any} changes Changes in the data input (detected by KeyValueDiffer).
* @return {{[name: string]: SimpleChange}} List of changes for the component.
*/
protected createChangesForComponent(changes: any): { [name: string]: SimpleChange } {
const newChanges: { [name: string]: SimpleChange } = {};
// Added items are considered first change.
changes.forEachAddedItem((item) => {
newChanges[item.key] = new SimpleChange(item.previousValue, item.currentValue, true);
});
// Changed or removed items aren't first change.
changes.forEachChangedItem((item) => {
newChanges[item.key] = new SimpleChange(item.previousValue, item.currentValue, false);
});
changes.forEachRemovedItem((item) => {
newChanges[item.key] = new SimpleChange(item.previousValue, item.currentValue, true);
});
return newChanges;
}
}

View File

@ -14,10 +14,11 @@
import {
Component, Input, OnInit, OnChanges, OnDestroy, ViewContainerRef, ViewChild, ComponentRef, SimpleChange, ChangeDetectorRef,
ElementRef, Optional, Output, EventEmitter
ElementRef, Optional, Output, EventEmitter, DoCheck, KeyValueDiffers
} from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreCompileProvider } from '../../providers/compile';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
/**
* This component has a behaviour similar to $compile for AngularJS. Given an HTML code, it will compile it so all its
@ -38,7 +39,7 @@ import { CoreCompileProvider } from '../../providers/compile';
selector: 'core-compile-html',
template: '<ng-container #dynamicComponent></ng-container>'
})
export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck {
@Input() text: string; // The HTML text to display.
@Input() javascript: string; // The Javascript to execute in the component.
@Input() jsData: any; // Data to pass to the fake component.
@ -50,11 +51,30 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
@ViewChild('dynamicComponent', { read: ViewContainerRef }) container: ViewContainerRef;
protected componentRef: ComponentRef<any>;
protected componentInstance: any;
protected element;
protected differ: any; // To detect changes in the jsData input.
constructor(protected compileProvider: CoreCompileProvider, protected cdr: ChangeDetectorRef, element: ElementRef,
@Optional() protected navCtrl: NavController) {
@Optional() protected navCtrl: NavController, differs: KeyValueDiffers, protected domUtils: CoreDomUtilsProvider) {
this.element = element.nativeElement;
this.differ = differs.find([]).create();
}
/**
* Detect and act upon changes that Angular cant or wont detect on its own (objects and arrays).
*/
ngDoCheck(): void {
if (this.componentInstance) {
// Check if there's any change in the jsData object.
const changes = this.differ.diff(this.jsData);
if (changes) {
this.setInputData();
if (this.componentInstance.ngOnChanges) {
this.componentInstance.ngOnChanges(this.domUtils.createChangesFromKeyValueDiff(changes));
}
}
}
}
/**
@ -96,6 +116,9 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
// Create the component, using the text as the template.
return class CoreCompileHtmlFakeComponent implements OnInit {
constructor() {
// Store this instance so it can be accessed by the outer component.
compileInstance.componentInstance = this;
// If there is some javascript to run, prepare the instance.
if (compileInstance.javascript) {
compileInstance.compileProvider.injectLibraries(this, compileInstance.extraProviders);
@ -107,9 +130,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
this['componentContainer'] = compileInstance.element;
// Add the data passed to the component.
for (const name in compileInstance.jsData) {
this[name] = compileInstance.jsData[name];
}
compileInstance.setInputData();
}
ngOnInit(): void {
@ -120,4 +141,15 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
}
};
}
/**
* Set the JS data as input data of the component instance.
*/
protected setInputData(): void {
if (this.componentInstance) {
for (const name in this.jsData) {
this.componentInstance[name] = this.jsData[name];
}
}
}
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Injectable, SimpleChange } from '@angular/core';
import {
LoadingController, Loading, ToastController, Toast, AlertController, Alert, Platform, Content,
ModalController
@ -148,6 +148,32 @@ export class CoreDomUtilsProvider {
return {coreCanceled: true};
}
/**
* Given a list of changes for a component input detected by a KeyValueDiffers, create an object similar to the one
* passed to the ngOnChanges functions.
*
* @param {any} changes Changes detected by KeyValueDiffer.
* @return {{[name: string]: SimpleChange}} Changes in a format like ngOnChanges.
*/
createChangesFromKeyValueDiff(changes: any): { [name: string]: SimpleChange } {
const newChanges: { [name: string]: SimpleChange } = {};
// Added items are considered first change.
changes.forEachAddedItem((item) => {
newChanges[item.key] = new SimpleChange(item.previousValue, item.currentValue, true);
});
// Changed or removed items aren't first change.
changes.forEachChangedItem((item) => {
newChanges[item.key] = new SimpleChange(item.previousValue, item.currentValue, false);
});
changes.forEachRemovedItem((item) => {
newChanges[item.key] = new SimpleChange(item.previousValue, item.currentValue, true);
});
return newChanges;
}
/**
* Extract the downloadable URLs from an HTML code.
*