feat(pipes): replaces iterable and key value diffing pipes with services

BREAKING CHANGE:
    Directives that previously injected Pipes to get iterableDiff or keyvalueDiff, now should inject IterableDiffers and KeyValueDiffers.
This commit is contained in:
vsavkin
2015-07-31 12:23:50 -07:00
parent c20a5d65d8
commit 392de4af67
20 changed files with 595 additions and 260 deletions
+35 -21
View File
@@ -1,11 +1,13 @@
import {isPresent, isString, StringWrapper, isBlank} from 'angular2/src/facade/lang';
import {Directive, LifecycleEvent} from 'angular2/annotations';
import {ElementRef} from 'angular2/core';
import {Pipes} from 'angular2/src/change_detection/pipes/pipes';
import {Pipe} from 'angular2/src/change_detection/pipes/pipe';
import {Renderer} from 'angular2/src/render/api';
import {KeyValueChanges} from 'angular2/src/change_detection/pipes/keyvalue_changes';
import {IterableChanges} from 'angular2/src/change_detection/pipes/iterable_changes';
import {isPresent, isString, StringWrapper} from 'angular2/src/facade/lang';
import {
KeyValueDiffer,
IterableDiffer,
IterableDiffers,
KeyValueDiffers
} from 'angular2/change_detection';
import {ListWrapper, StringMapWrapper, isListLikeIterable} from 'angular2/src/facade/collection';
/**
@@ -34,10 +36,12 @@ import {ListWrapper, StringMapWrapper, isListLikeIterable} from 'angular2/src/fa
properties: ['rawClass: class']
})
export class CSSClass {
_pipe: Pipe;
private _differ: any;
private _mode: string;
_rawClass;
constructor(private _pipes: Pipes, private _ngEl: ElementRef, private _renderer: Renderer) {}
constructor(private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers,
private _ngEl: ElementRef, private _renderer: Renderer) {}
set rawClass(v) {
this._cleanupClasses(this._rawClass);
@@ -47,16 +51,26 @@ export class CSSClass {
}
this._rawClass = v;
this._pipe = this._pipes.get(isListLikeIterable(v) ? 'iterableDiff' : 'keyValDiff', v);
if (isPresent(v)) {
if (isListLikeIterable(v)) {
this._differ = this._iterableDiffers.find(v).create(null);
this._mode = 'iterable';
} else {
this._differ = this._keyValueDiffers.find(v).create(null);
this._mode = 'keyValue';
}
}
}
onCheck(): void {
var diff = this._pipe.transform(this._rawClass, null);
if (isPresent(diff) && isPresent(diff.wrapped)) {
if (diff.wrapped instanceof IterableChanges) {
this._applyArrayChanges(diff.wrapped);
} else {
this._applyObjectChanges(diff.wrapped);
if (isPresent(this._differ)) {
var changes = this._differ.diff(this._rawClass);
if (isPresent(changes)) {
if (this._mode == 'iterable') {
this._applyIterableChanges(changes);
} else {
this._applyKeyValueChanges(changes);
}
}
}
}
@@ -75,19 +89,19 @@ export class CSSClass {
}
}
private _applyObjectChanges(diff: KeyValueChanges): void {
diff.forEachAddedItem((record) => { this._toggleClass(record.key, record.currentValue); });
diff.forEachChangedItem((record) => { this._toggleClass(record.key, record.currentValue); });
diff.forEachRemovedItem((record) => {
private _applyKeyValueChanges(changes: any): void {
changes.forEachAddedItem((record) => { this._toggleClass(record.key, record.currentValue); });
changes.forEachChangedItem((record) => { this._toggleClass(record.key, record.currentValue); });
changes.forEachRemovedItem((record) => {
if (record.previousValue) {
this._toggleClass(record.key, false);
}
});
}
private _applyArrayChanges(diff: IterableChanges): void {
diff.forEachAddedItem((record) => { this._toggleClass(record.item, true); });
diff.forEachRemovedItem((record) => { this._toggleClass(record.item, false); });
private _applyIterableChanges(changes: any): void {
changes.forEachAddedItem((record) => { this._toggleClass(record.item, true); });
changes.forEachRemovedItem((record) => { this._toggleClass(record.item, false); });
}
private _toggleClass(className: string, enabled): void {
+10 -11
View File
@@ -1,6 +1,6 @@
import {Directive, LifecycleEvent} from 'angular2/annotations';
import {ViewContainerRef, ViewRef, TemplateRef} from 'angular2/core';
import {ChangeDetectorRef, Pipe, Pipes} from 'angular2/change_detection';
import {ChangeDetectorRef, IterableDiffer, IterableDiffers} from 'angular2/change_detection';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
/**
@@ -37,27 +37,26 @@ import {isPresent, isBlank} from 'angular2/src/facade/lang';
{selector: '[ng-for][ng-for-of]', properties: ['ngForOf'], lifecycle: [LifecycleEvent.onCheck]})
export class NgFor {
_ngForOf: any;
_pipe: Pipe;
private _differ: IterableDiffer;
constructor(private viewContainer: ViewContainerRef, private templateRef: TemplateRef,
private pipes: Pipes, private cdr: ChangeDetectorRef) {}
private iterableDiffers: IterableDiffers, private cdr: ChangeDetectorRef) {}
set ngForOf(value: any) {
this._ngForOf = value;
this._pipe = this.pipes.get("iterableDiff", value, this.cdr, this._pipe);
if (isBlank(this._differ) && isPresent(value)) {
this._differ = this.iterableDiffers.find(value).create(this.cdr);
}
}
onCheck() {
var diff = this._pipe.transform(this._ngForOf, null);
if (isPresent(diff)) this._applyChanges(diff.wrapped);
if (isPresent(this._differ)) {
var changes = this._differ.diff(this._ngForOf);
if (isPresent(changes)) this._applyChanges(changes);
}
}
private _applyChanges(changes) {
if (isBlank(changes)) {
this.viewContainer.clear();
return;
}
// TODO(rado): check if change detection can produce a change record that is
// easier to consume than current.
var recordViewTuples = [];
+20 -17
View File
@@ -1,9 +1,7 @@
import {Directive, LifecycleEvent} from 'angular2/annotations';
import {ElementRef} from 'angular2/core';
import {Pipe} from 'angular2/src/change_detection/pipes/pipe';
import {Pipes} from 'angular2/src/change_detection/pipes/pipes';
import {KeyValueChanges} from 'angular2/src/change_detection/pipes/keyvalue_changes';
import {isPresent, print} from 'angular2/src/facade/lang';
import {KeyValueDiffer, KeyValueDiffers} from 'angular2/change_detection';
import {isPresent, isBlank, print} from 'angular2/src/facade/lang';
import {Renderer} from 'angular2/src/render/api';
/**
@@ -33,27 +31,32 @@ import {Renderer} from 'angular2/src/render/api';
properties: ['rawStyle: ng-style']
})
export class NgStyle {
_pipe: Pipe;
_rawStyle;
_differ: KeyValueDiffer;
constructor(private _pipes: Pipes, private _ngEl: ElementRef, private _renderer: Renderer) {}
constructor(private _differs: KeyValueDiffers, private _ngEl: ElementRef,
private _renderer: Renderer) {}
set rawStyle(v) {
this._rawStyle = v;
this._pipe = this._pipes.get('keyValDiff', this._rawStyle);
}
onCheck() {
var diff = this._pipe.transform(this._rawStyle, null);
if (isPresent(diff) && isPresent(diff.wrapped)) {
this._applyChanges(diff.wrapped);
if (isBlank(this._differ) && isPresent(v)) {
this._differ = this._differs.find(this._rawStyle).create(null);
}
}
private _applyChanges(diff: KeyValueChanges): void {
diff.forEachAddedItem((record) => { this._setStyle(record.key, record.currentValue); });
diff.forEachChangedItem((record) => { this._setStyle(record.key, record.currentValue); });
diff.forEachRemovedItem((record) => { this._setStyle(record.key, null); });
onCheck() {
if (isPresent(this._differ)) {
var changes = this._differ.diff(this._rawStyle);
if (isPresent(changes)) {
this._applyChanges(changes);
}
}
}
private _applyChanges(changes: any): void {
changes.forEachAddedItem((record) => { this._setStyle(record.key, record.currentValue); });
changes.forEachChangedItem((record) => { this._setStyle(record.key, record.currentValue); });
changes.forEachRemovedItem((record) => { this._setStyle(record.key, null); });
}
private _setStyle(name: string, val: string): void {
@@ -2,10 +2,10 @@ library angular2.directives.observable_list_iterable_diff;
import 'package:observe/observe.dart' show ObservableList;
import 'package:angular2/change_detection.dart';
import 'package:angular2/src/change_detection/pipes/iterable_changes.dart';
import 'package:angular2/src/change_detection/differs/default_iterable_differ.dart';
import 'dart:async';
class ObservableListDiff extends IterableChanges {
class ObservableListDiff extends DefaultIterableDiffer {
ChangeDetectorRef _ref;
ObservableListDiff(this._ref);
@@ -13,11 +13,6 @@ class ObservableListDiff extends IterableChanges {
ObservableList _collection;
StreamSubscription _subscription;
bool supports(obj) {
if (obj is ObservableList) return true;
throw "Cannot change the type of a collection";
}
onDestroy() {
if (this._subscription != null) {
this._subscription.cancel();
@@ -26,10 +21,14 @@ class ObservableListDiff extends IterableChanges {
}
}
dynamic transform(ObservableList collection, [List args]) {
dynamic diff(ObservableList collection) {
if (collection is! ObservableList) {
throw "Cannot change the type of a collection";
}
// A new collection instance is passed in.
// - We need to set up a listener.
// - We need to transform collection.
// - We need to diff collection.
if (!identical(_collection, collection)) {
_collection = collection;
@@ -39,14 +38,14 @@ class ObservableListDiff extends IterableChanges {
_ref.requestCheck();
});
_updated = false;
return super.transform(collection, args);
return super.diff(collection);
// An update has been registered since the last change detection check.
// - We reset the flag.
// - We diff the collection.
} else if (_updated) {
_updated = false;
return super.transform(collection, args);
return super.diff(collection);
// No updates has been registered.
// Returning this tells change detection that object has not change,
@@ -57,10 +56,10 @@ class ObservableListDiff extends IterableChanges {
}
}
class ObservableListDiffFactory implements PipeFactory {
class ObservableListDiffFactory implements IterableDifferFactory {
const ObservableListDiffFactory();
bool supports(obj) => obj is ObservableList;
Pipe create(ChangeDetectorRef cdRef) {
IterableDiffer create(ChangeDetectorRef cdRef) {
return new ObservableListDiff(cdRef);
}
}