feat(pipes): support arguments in transform function

This commit is contained in:
Pouria Alimirzaei 2015-06-26 00:22:06 +04:30 committed by vsavkin
parent f0e962c55e
commit 600d53c68e
19 changed files with 74 additions and 41 deletions

View File

@ -240,6 +240,8 @@ export class ChangeDetectorJITGenerator {
_genPipeCheck(r: ProtoRecord): string {
var context = this._localNames[r.contextIndex];
var argString = r.args.map((arg) => this._localNames[arg]).join(", ");
var oldValue = this._fieldNames[r.selfIndex];
var newValue = this._localNames[r.selfIndex];
var change = this._changeNames[r.selfIndex];
@ -259,7 +261,7 @@ export class ChangeDetectorJITGenerator {
${pipe} = ${PIPE_REGISTRY_ACCESSOR}.get('${pipeType}', ${context}, ${cdRef});
}
${newValue} = ${pipe}.transform(${context});
${newValue} = ${pipe}.transform(${context}, [${argString}]);
if (${oldValue} !== ${newValue}) {
${newValue} = ${UTIL}.unwrapValue(${newValue});
${change} = true;

View File

@ -233,10 +233,11 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
_pipeCheck(proto: ProtoRecord, throwOnChange: boolean) {
var context = this._readContext(proto);
var args = this._readArgs(proto);
var pipe = this._pipeFor(proto, context);
var prevValue = this._readSelf(proto);
var currValue = pipe.transform(context);
var currValue = pipe.transform(context, args);
if (!isSame(prevValue, currValue)) {
currValue = ChangeDetectionUtil.unwrapValue(currValue);

View File

@ -16,12 +16,13 @@ import {
} from 'angular2/src/facade/lang';
import {WrappedValue, Pipe, BasePipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
@CONST()
export class IterableChangesFactory implements PipeFactory {
supports(obj): boolean { return IterableChanges.supportsObj(obj); }
create(cdRef): Pipe { return new IterableChanges(); }
create(cdRef: ChangeDetectorRef): Pipe { return new IterableChanges(); }
}
/**
@ -89,7 +90,7 @@ export class IterableChanges extends BasePipe {
}
}
transform(collection): any {
transform(collection, args: List<any> = null): any {
if (this.check(collection)) {
return WrappedValue.wrap(this);
} else {

View File

@ -1,5 +1,6 @@
import {isBlank, isPresent, Json, CONST} from 'angular2/src/facade/lang';
import {Pipe, BasePipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
/**
* Implements json transforms to any object.
@ -27,8 +28,8 @@ import {Pipe, BasePipe, PipeFactory} from './pipe';
* @exportedAs angular2/pipes
*/
@CONST()
export class JsonPipe extends BasePipe {
transform(value): string { return Json.stringify(value); }
export class JsonPipe extends BasePipe implements PipeFactory {
transform(value, args: List<any> = null): string { return Json.stringify(value); }
create(cdRef): Pipe { return this }
create(cdRef: ChangeDetectorRef): Pipe { return this }
}

View File

@ -1,6 +1,6 @@
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {stringify, looseIdentical, isJsObject, CONST} from 'angular2/src/facade/lang';
import {ChangeDetectorRef} from '../change_detector_ref';
import {WrappedValue, BasePipe, Pipe, PipeFactory} from './pipe';
/**
@ -10,7 +10,7 @@ import {WrappedValue, BasePipe, Pipe, PipeFactory} from './pipe';
export class KeyValueChangesFactory implements PipeFactory {
supports(obj): boolean { return KeyValueChanges.supportsObj(obj); }
create(cdRef): Pipe { return new KeyValueChanges(); }
create(cdRef: ChangeDetectorRef): Pipe { return new KeyValueChanges(); }
}
/**
@ -31,7 +31,7 @@ export class KeyValueChanges extends BasePipe {
supports(obj): boolean { return KeyValueChanges.supportsObj(obj); }
transform(map): any {
transform(map, args: List<any> = null): any {
if (this.check(map)) {
return WrappedValue.wrap(this);
} else {

View File

@ -1,5 +1,6 @@
import {isString, StringWrapper, CONST} from 'angular2/src/facade/lang';
import {Pipe} from './pipe';
import {Pipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
/**
* Implements lowercase transforms to text.
@ -30,7 +31,7 @@ export class LowerCasePipe implements Pipe {
onDestroy(): void { this._latestValue = null; }
transform(value: string): string {
transform(value: string, args: List<any> = null): string {
if (this._latestValue !== value) {
this._latestValue = value;
return StringWrapper.toLowerCase(value);
@ -44,8 +45,8 @@ export class LowerCasePipe implements Pipe {
* @exportedAs angular2/pipes
*/
@CONST()
export class LowerCaseFactory {
export class LowerCaseFactory implements PipeFactory {
supports(str): boolean { return isString(str); }
create(): Pipe { return new LowerCasePipe(); }
create(cdRef: ChangeDetectorRef): Pipe { return new LowerCasePipe(); }
}

View File

@ -1,5 +1,6 @@
import {isBlank, CONST} from 'angular2/src/facade/lang';
import {Pipe, BasePipe, WrappedValue, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
/**
* @exportedAs angular2/pipes
@ -8,7 +9,7 @@ import {Pipe, BasePipe, WrappedValue, PipeFactory} from './pipe';
export class NullPipeFactory implements PipeFactory {
supports(obj): boolean { return NullPipe.supportsObj(obj); }
create(cdRef): Pipe { return new NullPipe(); }
create(cdRef: ChangeDetectorRef): Pipe { return new NullPipe(); }
}
/**
@ -21,7 +22,7 @@ export class NullPipe extends BasePipe {
supports(obj): boolean { return NullPipe.supportsObj(obj); }
transform(value): WrappedValue {
transform(value, args: List<any> = null): WrappedValue {
if (!this.called) {
this.called = true;
return WrappedValue.wrap(null);

View File

@ -46,7 +46,7 @@ export class ObservablePipe implements Pipe {
}
}
transform(obs: Observable): any {
transform(obs: Observable, args: List<any> = null): any {
if (isBlank(this._subscription)) {
this._subscribe(obs);
return null;
@ -94,5 +94,5 @@ export class ObservablePipe implements Pipe {
export class ObservablePipeFactory implements PipeFactory {
supports(obs): boolean { return ObservableWrapper.isObservable(obs); }
create(cdRef): Pipe { return new ObservablePipe(cdRef); }
create(cdRef: ChangeDetectorRef): Pipe { return new ObservablePipe(cdRef); }
}

View File

@ -1,4 +1,5 @@
import {ABSTRACT, BaseException, CONST} from 'angular2/src/facade/lang';
import {ChangeDetectorRef} from '../change_detector_ref';
/**
* Indicates that the result of a {@link Pipe} transformation has changed even though the reference
@ -43,7 +44,7 @@ var _wrappedIndex = 0;
*
* onDestroy() {}
*
* transform(value) {
* transform(value, args = []) {
* return `${value}${value}`;
* }
* }
@ -54,7 +55,7 @@ var _wrappedIndex = 0;
export interface Pipe {
supports(obj): boolean;
onDestroy(): void;
transform(value: any): any;
transform(value: any, args: List<any>): any;
}
/**
@ -74,12 +75,12 @@ export interface Pipe {
export class BasePipe implements Pipe {
supports(obj): boolean { return true; }
onDestroy(): void {}
transform(value: any): any { return _abstract(); }
transform(value: any, args: List<any>): any { return _abstract(); }
}
export interface PipeFactory {
supports(obs): boolean;
create(cdRef): Pipe;
create(cdRef: ChangeDetectorRef): Pipe;
}
function _abstract() {

View File

@ -1,6 +1,6 @@
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {isBlank, isPresent, isPromise, CONST} from 'angular2/src/facade/lang';
import {Pipe, WrappedValue} from './pipe';
import {Pipe, PipeFactory, WrappedValue} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
/**
@ -45,7 +45,7 @@ export class PromisePipe implements Pipe {
}
}
transform(promise: Promise<any>): any {
transform(promise: Promise<any>, args: List<any> = null): any {
if (isBlank(this._sourcePromise)) {
this._sourcePromise = promise;
promise.then((val) => {
@ -81,8 +81,8 @@ export class PromisePipe implements Pipe {
* @exportedAs angular2/pipes
*/
@CONST()
export class PromisePipeFactory {
export class PromisePipeFactory implements PipeFactory {
supports(promise): boolean { return isPromise(promise); }
create(cdRef): Pipe { return new PromisePipe(cdRef); }
create(cdRef: ChangeDetectorRef): Pipe { return new PromisePipe(cdRef); }
}

View File

@ -1,5 +1,6 @@
import {isString, StringWrapper, CONST} from 'angular2/src/facade/lang';
import {Pipe} from './pipe';
import {Pipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
/**
* Implements uppercase transforms to text.
@ -30,7 +31,7 @@ export class UpperCasePipe implements Pipe {
onDestroy(): void { this._latestValue = null; }
transform(value: string): string {
transform(value: string, args: List<any> = null): string {
if (this._latestValue !== value) {
this._latestValue = value;
return StringWrapper.toUpperCase(value);
@ -44,8 +45,8 @@ export class UpperCasePipe implements Pipe {
* @exportedAs angular2/pipes
*/
@CONST()
export class UpperCaseFactory {
export class UpperCaseFactory implements PipeFactory {
supports(str): boolean { return isString(str); }
create(): Pipe { return new UpperCasePipe(); }
create(cdRef: ChangeDetectorRef): Pipe { return new UpperCasePipe(); }
}

View File

@ -181,7 +181,8 @@ class _ConvertAstIntoProtoRecords implements AstVisitor {
visitPipe(ast: BindingPipe): number {
var value = ast.exp.visit(this);
return this._addRecord(RecordType.PIPE, ast.name, ast.name, [], null, value);
var args = this._visitAll(ast.args);
return this._addRecord(RecordType.PIPE, ast.name, ast.name, args, null, value);
}
visitKeyedAccess(ast: KeyedAccess): number {

View File

@ -28,7 +28,7 @@ export class CSSClass {
}
onCheck(): void {
var diff = this._pipe.transform(this._rawClass);
var diff = this._pipe.transform(this._rawClass, null);
if (isPresent(diff) && isPresent(diff.wrapped)) {
if (diff.wrapped instanceof IterableChanges) {
this._applyArrayChanges(diff.wrapped);

View File

@ -55,7 +55,7 @@ export class NgFor {
}
onCheck() {
var diff = this._pipe.transform(this._ngForOf);
var diff = this._pipe.transform(this._ngForOf, null);
if (isPresent(diff)) this._applyChanges(diff.wrapped);
}

View File

@ -20,7 +20,7 @@ export class NgStyle {
}
onCheck() {
var diff = this._pipe.transform(this._rawStyle);
var diff = this._pipe.transform(this._rawStyle, null);
if (isPresent(diff) && isPresent(diff.wrapped)) {
this._applyChanges(diff.wrapped);
}

View File

@ -304,6 +304,8 @@ class _CodegenState {
String _genPipeCheck(ProtoRecord r) {
var context = _localNames[r.contextIndex];
var argString = r.args.map((arg) => this._localNames[arg]).join(", ");
var oldValue = _fieldNames[r.selfIndex];
var newValue = _localNames[r.selfIndex];
var change = _changeNames[r.selfIndex];
@ -322,7 +324,7 @@ class _CodegenState {
$pipe = $_PIPE_REGISTRY_ACCESSOR.get('$pipeType', $context, $cdRef);
}
$newValue = $pipe.transform($context);
$newValue = $pipe.transform($context, [$argString]);
if (!$_IDENTICAL_CHECK_FN($oldValue, $newValue)) {
$newValue = $_UTIL.unwrapValue($newValue);
$change = true;

View File

@ -300,6 +300,7 @@ var _availableDefinitions = [
'{z: 1}',
'{z: a}',
'name | pipe',
"name | pipe:'one':address.city",
'value',
'a',
'address.city',

View File

@ -333,6 +333,15 @@ export function main() {
val.changeDetector.detectChanges();
expect(val.dispatcher.loggedValues).toEqual(['bob state:0']);
});
it('should support arguments in pipes', () => {
var registry = new FakePipeRegistry('pipe', () => new MultiArgPipe());
var address = new Address('two');
var person = new Person('value', address);
var val = _createChangeDetector("name | pipe:'one':address.city", person, registry);
val.changeDetector.detectChanges();
expect(val.dispatcher.loggedValues).toEqual(['value one two default']);
});
});
it('should notify the dispatcher on all changes done', () => {
@ -861,7 +870,7 @@ class CountingPipe implements Pipe {
supports(newValue) { return true; }
transform(value) { return `${value} state:${this.state ++}`; }
transform(value, args = null) { return `${value} state:${this.state ++}`; }
}
class OncePipe implements Pipe {
@ -872,7 +881,7 @@ class OncePipe implements Pipe {
onDestroy() { this.destroyCalled = true; }
transform(value) {
transform(value, args = null) {
this.called = true;
return value;
}
@ -883,7 +892,7 @@ class IdentityPipe implements Pipe {
onDestroy() {}
transform(value) { return value; }
transform(value, args = null) { return value; }
}
class WrappedPipe implements Pipe {
@ -891,7 +900,18 @@ class WrappedPipe implements Pipe {
onDestroy() {}
transform(value) { return WrappedValue.wrap(value); }
transform(value, args = null) { return WrappedValue.wrap(value); }
}
class MultiArgPipe implements Pipe {
transform(value, args = null) {
var arg1 = args[0];
var arg2 = args[1];
var arg3 = args.length > 2 ? args[2] : 'default';
return `${value} ${arg1} ${arg2} ${arg3}`;
}
supports(obj): boolean { return true; }
onDestroy(): void {}
}
class FakePipeRegistry extends PipeRegistry {

View File

@ -1473,7 +1473,7 @@ class DoublePipe implements Pipe {
supports(obj) { return true; }
transform(value) { return `${value}${value}`; }
transform(value, args = null) { return `${value}${value}`; }
}
@Injectable()