feat(pipes): changed PipeTransform to make onDestroy optional
BREAKING CHANGE: Before: Angular called onDestroy on all pipes. After: Angular calls onDestroy only on pipes that have the onDestroy method.
This commit is contained in:
parent
ac311911c0
commit
839edaa15b
@ -44,7 +44,7 @@ export {DynamicChangeDetector} from './dynamic_change_detector';
|
||||
export {ChangeDetectorRef} from './change_detector_ref';
|
||||
export {IterableDiffers, IterableDiffer, IterableDifferFactory} from './differs/iterable_differs';
|
||||
export {KeyValueDiffers, KeyValueDiffer, KeyValueDifferFactory} from './differs/keyvalue_differs';
|
||||
export {PipeTransform, BasePipeTransform} from './pipe_transform';
|
||||
export {PipeTransform, PipeOnDestroy, BasePipeTransform} from './pipe_transform';
|
||||
export {WrappedValue} from './change_detection_util';
|
||||
|
||||
/**
|
||||
|
@ -2,6 +2,7 @@ import {CONST_EXPR, isPresent, isBlank, BaseException, Type} from 'angular2/src/
|
||||
import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {ProtoRecord} from './proto_record';
|
||||
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
|
||||
import {implementsOnDestroy} from './pipe_lifecycle_reflector';
|
||||
|
||||
|
||||
/**
|
||||
@ -180,4 +181,10 @@ export class ChangeDetectionUtil {
|
||||
null :
|
||||
protos[selfIndex - 1]; // self index is shifted by one because of context
|
||||
}
|
||||
|
||||
static callPipeOnDestroy(pipe: any): void {
|
||||
if (implementsOnDestroy(pipe)) {
|
||||
pipe.onDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,9 +146,13 @@ export class CodegenNameUtil {
|
||||
* Generates statements destroying all pipe variables.
|
||||
*/
|
||||
genPipeOnDestroy(): string {
|
||||
return ListWrapper.join(ListWrapper.map(ListWrapper.filter(this.records, (r) => {
|
||||
return r.isPipeRecord();
|
||||
}), (r) => { return `${this.getPipeName(r.selfIndex)}.onDestroy();`; }), '\n');
|
||||
return ListWrapper.join(
|
||||
ListWrapper.map(
|
||||
ListWrapper.filter(this.records, (r) => { return r.isPipeRecord(); }),
|
||||
(r) => {
|
||||
return `${this.utilName}.callPipeOnDestroy(${this.getPipeName(r.selfIndex)});`;
|
||||
}),
|
||||
'\n');
|
||||
}
|
||||
|
||||
getPipeName(idx: int): string {
|
||||
|
@ -48,7 +48,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||
_destroyPipes() {
|
||||
for (var i = 0; i < this.localPipes.length; ++i) {
|
||||
if (isPresent(this.localPipes[i])) {
|
||||
this.localPipes[i].onDestroy();
|
||||
ChangeDetectionUtil.callPipeOnDestroy(this.localPipes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
library angular2.core.compiler.pipe_lifecycle_reflector;
|
||||
|
||||
import 'package:angular2/src/change_detection/pipe_transform.dart';
|
||||
|
||||
bool implementsOnDestroy(Object pipe) => pipe is PipeOnDestroy;
|
@ -0,0 +1,3 @@
|
||||
export function implementsOnDestroy(pipe: any): boolean {
|
||||
return pipe.constructor.prototype.onDestroy;
|
||||
}
|
@ -7,19 +7,36 @@ import {ABSTRACT, BaseException, CONST, Type} from 'angular2/src/facade/lang';
|
||||
*
|
||||
* ```
|
||||
* class DoublePipe implements PipeTransform {
|
||||
* onDestroy() {}
|
||||
*
|
||||
* transform(value, args = []) {
|
||||
* return `${value}${value}`;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export interface PipeTransform {
|
||||
onDestroy(): void;
|
||||
export interface PipeTransform { transform(value: any, args: List<any>): any; }
|
||||
|
||||
transform(value: any, args: List<any>): any;
|
||||
}
|
||||
/**
|
||||
* An interface that stateful pipes should implement.
|
||||
*
|
||||
* #Example
|
||||
*
|
||||
* ```
|
||||
* class StatefulPipe implements PipeTransform, PipeOnDestroy {
|
||||
* connection;
|
||||
*
|
||||
* onDestroy() {
|
||||
* this.connection.release();
|
||||
* }
|
||||
*
|
||||
* transform(value, args = []) {
|
||||
* this.connection = createConnection();
|
||||
* // ...
|
||||
* return someValue;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export interface PipeOnDestroy { onDestroy(): void; }
|
||||
|
||||
/**
|
||||
* Provides default implementation of the `onDestroy` method.
|
||||
@ -35,7 +52,7 @@ export interface PipeTransform {
|
||||
* ```
|
||||
*/
|
||||
@CONST()
|
||||
export class BasePipeTransform implements PipeTransform {
|
||||
export class BasePipeTransform implements PipeTransform, PipeOnDestroy {
|
||||
onDestroy(): void {}
|
||||
transform(value: any, args: List<any>): any { return _abstract(); }
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import {
|
||||
DirectiveRecord,
|
||||
DirectiveIndex,
|
||||
PipeTransform,
|
||||
PipeOnDestroy,
|
||||
CHECK_ALWAYS,
|
||||
CHECK_ONCE,
|
||||
CHECKED,
|
||||
@ -768,7 +769,7 @@ export function main() {
|
||||
expect(cd.hydrated()).toBe(true);
|
||||
});
|
||||
|
||||
it('should destroy all active pipes during dehyration', () => {
|
||||
it('should destroy all active pipes implementing onDestroy during dehyration', () => {
|
||||
var pipe = new PipeWithOnDestroy();
|
||||
var registry = new FakePipes('pipe', () => pipe);
|
||||
var cd = _createChangeDetector('name | pipe', new Person('bob'), registry).changeDetector;
|
||||
@ -779,6 +780,15 @@ export function main() {
|
||||
expect(pipe.destroyCalled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not call onDestroy all pipes that do not implement onDestroy', () => {
|
||||
var pipe = new CountingPipe();
|
||||
var registry = new FakePipes('pipe', () => pipe);
|
||||
var cd = _createChangeDetector('name | pipe', new Person('bob'), registry).changeDetector;
|
||||
|
||||
cd.detectChanges();
|
||||
expect(() => cd.dehydrate()).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw when detectChanges is called on a dehydrated detector', () => {
|
||||
var context = new Person('Bob');
|
||||
var val = _createChangeDetector('name', context);
|
||||
@ -844,11 +854,10 @@ export function main() {
|
||||
|
||||
class CountingPipe implements PipeTransform {
|
||||
state: number = 0;
|
||||
onDestroy() {}
|
||||
transform(value, args = null) { return `${value} state:${this.state ++}`; }
|
||||
}
|
||||
|
||||
class PipeWithOnDestroy implements PipeTransform {
|
||||
class PipeWithOnDestroy implements PipeTransform, PipeOnDestroy {
|
||||
destroyCalled: boolean = false;
|
||||
onDestroy() { this.destroyCalled = true; }
|
||||
|
||||
@ -856,12 +865,10 @@ class PipeWithOnDestroy implements PipeTransform {
|
||||
}
|
||||
|
||||
class IdentityPipe implements PipeTransform {
|
||||
onDestroy() {}
|
||||
transform(value, args = null) { return value; }
|
||||
}
|
||||
|
||||
class WrappedPipe implements PipeTransform {
|
||||
onDestroy() {}
|
||||
transform(value, args = null) { return WrappedValue.wrap(value); }
|
||||
}
|
||||
|
||||
@ -872,7 +879,6 @@ class MultiArgPipe implements PipeTransform {
|
||||
var arg3 = args.length > 2 ? args[2] : 'default';
|
||||
return `${value} ${arg1} ${arg2} ${arg3}`;
|
||||
}
|
||||
onDestroy(): void {}
|
||||
}
|
||||
|
||||
class FakePipes implements Pipes {
|
||||
|
Loading…
x
Reference in New Issue
Block a user