Skip to content

Commit

Permalink
feat(events): listen and notify Angular of object and array mutations
Browse files Browse the repository at this point in the history
Fixes #9
  • Loading branch information
hotforfeature committed Apr 12, 2017
1 parent 3922ea7 commit 95dedf3
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 19 deletions.
28 changes: 18 additions & 10 deletions src/events/polymer-property.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { } from '../util/Polymer';
import { OnPolymerChange } from './on-polymer-change';

export function PolymerProperty(): PropertyDecorator {
Expand All @@ -18,18 +19,25 @@ export function PolymerProperty(): PropertyDecorator {
return value;
}
},
set(valueOrEvent: any|CustomEvent) {
let newValue = unwrapPolymerEvent(valueOrEvent);
if (desc && desc.set) {
desc.set(newValue);
}
set(event: any|CustomEvent) {
if (event instanceof CustomEvent && event.detail.path) {
// Object or Array mutation, we need to tell Angular that things have changed
if ((<OnPolymerChange>this).onPolymerChange && event instanceof CustomEvent) {
(<OnPolymerChange>this).onPolymerChange(propertyKey, value, event.detail);
}
} else {
let newValue = unwrapPolymerEvent(event);
if (desc && desc.set) {
desc.set(newValue);
}

if (newValue !== value) {
// Even if there is a setter, we still keep a copy to determine if a change happens
value = newValue;
if (newValue !== value) {
// Even if there is a setter, we still keep a copy to determine if a change happens
value = newValue;

if ((<OnPolymerChange>this).onPolymerChange && valueOrEvent instanceof CustomEvent) {
(<OnPolymerChange>this).onPolymerChange(propertyKey, valueOrEvent, valueOrEvent.detail);
if ((<OnPolymerChange>this).onPolymerChange && event instanceof CustomEvent) {
(<OnPolymerChange>this).onPolymerChange(propertyKey, event, event.detail);
}
}
}
}
Expand Down
29 changes: 20 additions & 9 deletions src/events/polymer.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,24 @@ export class PolymerDirective implements OnInit {
ngOnInit() {
const klass = getCustomElementClass(this.elementRef);
if (klass) {
// Setup Polymer to Angular event mapping
let notify = [];
notify = notify.concat(...this.getNotifyProperties(klass.prototype.properties || {}));
const properties = {};
this.copyKeysFrom(klass.prototype.properties, properties);
if (klass.prototype.behaviors) {
klass.prototype.behaviors.forEach(behavior => {
notify = notify.concat(...this.getNotifyProperties(behavior.properties || {}));
klass.prototype.behaviors.map(behavior => {
return behavior.properties || [];
}).forEach(property => {
this.copyKeysFrom(property, properties);
});
}

notify.forEach(property => {
// Listen for notify properties and Object/Array properties which may issue path changes
const changeable = Object.keys(properties).filter(propertyName => {
const property = properties[propertyName];
return property.notify || property === Object || property.type === Object ||
property === Array || property.type === Array;
});

changeable.forEach(property => {
const eventName = `${window.Polymer.CaseMap.camelToDashCase(property)}-changed`;
this.elementRef.nativeElement.addEventListener(eventName, event => {
this.elementRef.nativeElement.dispatchEvent(new CustomEvent(`${property}Change`, {
Expand All @@ -32,9 +40,12 @@ export class PolymerDirective implements OnInit {
}
}

private getNotifyProperties(properties: any): string[] {
return Object.keys(properties).filter(property => {
return properties[property].notify;
private copyKeysFrom(from: any, to: any): any {
Object.keys(from || {}).forEach(key => {
if (key[0] !== '_') {
// Only copy public properties
to[key] = from[key];
}
});
}
}
2 changes: 2 additions & 0 deletions src/origami.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export * from './forms/iron-control';
export * from './polymer.module';
export * from './style/custom-style.service';
export * from './templates/polymer-template';
export * from './util/customElements';
export * from './util/Polymer';
37 changes: 37 additions & 0 deletions src/util/Polymer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,47 @@ export namespace Polymer {
camelToDashCase(camel: string): string;
dashToCamelCase(dash: string): string;
}

export type PathLike = string|Array<string|number>;

export interface Path {
isPath(path: string): boolean;
root(path: string): string;
isAncestor(base: string, path: string): boolean;
isDescendant(base: string, path: string): boolean;
translate(base: string, newBase: string, path: string): string;
matches(base: string, path: string): boolean;
normalize(path: PathLike): string;
split(path: PathLike): string[];
get(root: any, path: PathLike, info?: any): any;
set(root: any, path: PathLike, info?: any): string;
}

export interface Splice<T> {
index: number;
addedCount: number;
removed: T[];
object: T[];
type: 'splice';
}

export interface PropertyEffects {
setProperties(props: Object);
notifySplices<T>(path: PathLike, splices: Array<Splice<T>>);
get(path: PathLike, root?: any): any;
set(path: PathLike, value: any, root?: any);
push<T>(path: PathLike, ...items: T[]): number;
pop(path: PathLike): any;
splice<T>(path: PathLike, start: number, deleteCount: number, ...items: T[]): T[];
shift(path: PathLike): any;
unshift<T>(path: PathLike, ...items: T[]): number;
notifyPath(path: PathLike, value?: any);
}
}

export interface Polymer {
CaseMap: Polymer.CaseMap;
Path: Polymer.Path;
}

declare global {
Expand Down

0 comments on commit 95dedf3

Please sign in to comment.