X Tutup
Skip to content

Commit e8e430e

Browse files
committed
feat(change_detection): added support for observable components and directives
1 parent 85ec34d commit e8e430e

File tree

11 files changed

+202
-105
lines changed

11 files changed

+202
-105
lines changed

modules/angular2/src/change_detection/abstract_change_detector.ts

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {Locals} from './parser/locals';
1515
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from './constants';
1616
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
1717
import {isObservable} from './observable_facade';
18+
import {ON_PUSH_OBSERVE} from './constants';
19+
1820

1921
var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
2022

@@ -44,7 +46,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
4446

4547
constructor(public id: string, public dispatcher: ChangeDispatcher,
4648
public numberOfPropertyProtoRecords: number, public bindingTargets: BindingTarget[],
47-
public directiveIndices: DirectiveIndex[], public modeOnHydrate: string) {
49+
public directiveIndices: DirectiveIndex[], public strategy: string) {
4850
this.ref = new ChangeDetectorRef(this);
4951
}
5052

@@ -116,8 +118,13 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
116118
// This method is not intended to be overridden. Subclasses should instead provide an
117119
// implementation of `hydrateDirectives`.
118120
hydrate(context: T, locals: Locals, directives: any, pipes: any): void {
119-
this.mode = this.modeOnHydrate;
121+
this.mode = ChangeDetectionUtil.changeDetectionMode(this.strategy);
120122
this.context = context;
123+
124+
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
125+
this.observeComponent(context);
126+
}
127+
121128
this.locals = locals;
122129
this.pipes = pipes;
123130
this.hydrateDirectives(directives);
@@ -133,7 +140,9 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
133140
this.dehydrateDirectives(true);
134141

135142
// This is an experimental feature. Works only in Dart.
136-
this.unsubsribeFromObservables();
143+
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
144+
this._unsubsribeFromObservables();
145+
}
137146

138147
this.context = null;
139148
this.locals = null;
@@ -172,7 +181,8 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
172181
}
173182
}
174183

175-
private unsubsribeFromObservables(): void {
184+
// This is an experimental feature. Works only in Dart.
185+
private _unsubsribeFromObservables(): void {
176186
if (isPresent(this.subscriptions)) {
177187
for (var i = 0; i < this.subscriptions.length; ++i) {
178188
var s = this.subscriptions[i];
@@ -185,12 +195,9 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
185195
}
186196

187197
// This is an experimental feature. Works only in Dart.
188-
protected observe(value: any, index: number): any {
198+
protected observeValue(value: any, index: number): any {
189199
if (isObservable(value)) {
190-
if (isBlank(this.subscriptions)) {
191-
this.subscriptions = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords + 1);
192-
this.streams = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords + 1);
193-
}
200+
this._createArrayToStoreObservables();
194201
if (isBlank(this.subscriptions[index])) {
195202
this.streams[index] = value.changes;
196203
this.subscriptions[index] = value.changes.listen((_) => this.ref.requestCheck());
@@ -203,6 +210,41 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
203210
return value;
204211
}
205212

213+
// This is an experimental feature. Works only in Dart.
214+
protected observeDirective(value: any, index: number): any {
215+
if (isObservable(value)) {
216+
this._createArrayToStoreObservables();
217+
var arrayIndex = this.numberOfPropertyProtoRecords + index + 2; // +1 is component
218+
this.streams[arrayIndex] = value.changes;
219+
this.subscriptions[arrayIndex] = value.changes.listen((_) => this.ref.requestCheck());
220+
}
221+
return value;
222+
}
223+
224+
// This is an experimental feature. Works only in Dart.
225+
protected observeComponent(value: any): any {
226+
if (isObservable(value)) {
227+
this._createArrayToStoreObservables();
228+
var index = this.numberOfPropertyProtoRecords + 1;
229+
this.streams[index] = value.changes;
230+
this.subscriptions[index] = value.changes.listen((_) => this.ref.requestCheck());
231+
}
232+
return value;
233+
}
234+
235+
private _createArrayToStoreObservables(): void {
236+
if (isBlank(this.subscriptions)) {
237+
this.subscriptions = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords +
238+
this.directiveIndices.length + 2);
239+
this.streams = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords +
240+
this.directiveIndices.length + 2);
241+
}
242+
}
243+
244+
protected getDirectiveFor(directives: any, index: number): any {
245+
return directives.getDirectiveFor(this.directiveIndices[index]);
246+
}
247+
206248
protected getDetectorFor(directives: any, index: number): ChangeDetector {
207249
return directives.getDetectorFor(this.directiveIndices[index]);
208250
}

modules/angular2/src/change_detection/change_detection_jit_generator.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {DirectiveIndex, DirectiveRecord} from './directive_record';
88
import {ProtoRecord, RecordType} from './proto_record';
99
import {CodegenNameUtil, sanitizeName} from './codegen_name_util';
1010
import {CodegenLogicUtil} from './codegen_logic_util';
11+
import {codify} from './codegen_facade';
1112
import {EventBinding} from './event_binding';
1213
import {BindingTarget} from './binding_record';
1314
import {ChangeDetectorGenConfig} from './interfaces';
@@ -48,7 +49,7 @@ export class ChangeDetectorJITGenerator {
4849
${ABSTRACT_CHANGE_DETECTOR}.call(
4950
this, ${JSON.stringify(this.id)}, dispatcher, ${this.records.length},
5051
${this._typeName}.gen_propertyBindingTargets, ${this._typeName}.gen_directiveIndices,
51-
"${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}");
52+
${codify(this.changeDetectionStrategy)});
5253
this.dehydrateDirectives(false);
5354
}
5455
@@ -160,7 +161,7 @@ export class ChangeDetectorJITGenerator {
160161
}
161162

162163
_maybeGenHydrateDirectives(): string {
163-
var hydrateDirectivesCode = this._genHydrateDirectives();
164+
var hydrateDirectivesCode = this._logic.genHydrateDirectives(this.directiveRecords);
164165
var hydrateDetectorsCode = this._logic.genHydrateDetectors(this.directiveRecords);
165166
if (!hydrateDirectivesCode && !hydrateDetectorsCode) return '';
166167
return `${this._typeName}.prototype.hydrateDirectives = function(directives) {
@@ -169,16 +170,6 @@ export class ChangeDetectorJITGenerator {
169170
}`;
170171
}
171172

172-
_genHydrateDirectives(): string {
173-
var directiveFieldNames = this._names.getAllDirectiveNames();
174-
var lines = ListWrapper.createFixedSize(directiveFieldNames.length);
175-
for (var i = 0, iLen = directiveFieldNames.length; i < iLen; ++i) {
176-
lines[i] = `${directiveFieldNames[i]} = directives.getDirectiveFor(
177-
${this._names.getDirectivesAccessorName()}[${i}]);`;
178-
}
179-
return lines.join('\n');
180-
}
181-
182173
_maybeGenCallOnAllChangesDone(): string {
183174
var notifications = [];
184175
var dirs = this.directiveRecords;

modules/angular2/src/change_detection/codegen_logic_util.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@ import {codify, combineGeneratedStrings, rawString} from './codegen_facade';
55
import {ProtoRecord, RecordType} from './proto_record';
66
import {BindingTarget} from './binding_record';
77
import {DirectiveRecord} from './directive_record';
8-
9-
/**
10-
* This is an experimental feature. Works only in Dart.
11-
*/
12-
const ON_PUSH_OBSERVE = "ON_PUSH_OBSERVE";
8+
import {ON_PUSH_OBSERVE} from './constants';
139

1410
/**
1511
* Class responsible for providing change detection logic for chagne detector classes.
@@ -118,7 +114,7 @@ export class CodegenLogicUtil {
118114
_observe(exp: string, rec: ProtoRecord): string {
119115
// This is an experimental feature. Works only in Dart.
120116
if (StringWrapper.equals(this._changeDetection, ON_PUSH_OBSERVE)) {
121-
return `this.observe(${exp}, ${rec.selfIndex})`;
117+
return `this.observeValue(${exp}, ${rec.selfIndex})`;
122118
} else {
123119
return exp;
124120
}
@@ -152,6 +148,24 @@ export class CodegenLogicUtil {
152148
return combineGeneratedStrings(iVals);
153149
}
154150

151+
genHydrateDirectives(directiveRecords: DirectiveRecord[]): string {
152+
var res = [];
153+
for (var i = 0; i < directiveRecords.length; ++i) {
154+
var r = directiveRecords[i];
155+
res.push(`${this._names.getDirectiveName(r.directiveIndex)} = ${this._genReadDirective(i)};`);
156+
}
157+
return res.join("\n");
158+
}
159+
160+
private _genReadDirective(index: number) {
161+
// This is an experimental feature. Works only in Dart.
162+
if (StringWrapper.equals(this._changeDetection, ON_PUSH_OBSERVE)) {
163+
return `this.observeDirective(this.getDirectiveFor(directives, ${index}), ${index})`;
164+
} else {
165+
return `this.getDirectiveFor(directives, ${index})`;
166+
}
167+
}
168+
155169
genHydrateDetectors(directiveRecords: DirectiveRecord[]): string {
156170
var res = [];
157171
for (var i = 0; i < directiveRecords.length; ++i) {

modules/angular2/src/change_detection/codegen_name_util.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,6 @@ export class CodegenNameUtil {
190190
return this._addFieldPrefix(`${this._sanitizedNames[idx]}_pipe`);
191191
}
192192

193-
getAllDirectiveNames(): List<string> {
194-
return ListWrapper.map(this.directiveRecords, d => this.getDirectiveName(d.directiveIndex));
195-
}
196-
197193
getDirectiveName(d: DirectiveIndex): string {
198194
return this._addFieldPrefix(`directive_${d.name}`);
199195
}

modules/angular2/src/change_detection/constants.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,10 @@ export const DEFAULT: string = "DEFAULT";
3737

3838
export function isDefaultChangeDetectionStrategy(changeDetectionStrategy: string): boolean {
3939
return isBlank(changeDetectionStrategy) || StringWrapper.equals(changeDetectionStrategy, DEFAULT);
40-
}
40+
}
41+
42+
43+
/**
44+
* This is an experimental feature. Works only in Dart.
45+
*/
46+
export const ON_PUSH_OBSERVE = "ON_PUSH_OBSERVE";

modules/angular2/src/change_detection/dynamic_change_detector.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {DirectiveRecord, DirectiveIndex} from './directive_record';
1414
import {Locals} from './parser/locals';
1515
import {ChangeDetectorGenConfig} from './interfaces';
1616
import {ChangeDetectionUtil, SimpleChange} from './change_detection_util';
17-
17+
import {ON_PUSH_OBSERVE} from './constants';
1818
import {ProtoRecord, RecordType} from './proto_record';
1919

2020
export class DynamicChangeDetector extends AbstractChangeDetector<any> {
@@ -26,11 +26,11 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
2626

2727
constructor(id: string, dispatcher: any, numberOfPropertyProtoRecords: number,
2828
propertyBindingTargets: BindingTarget[], directiveIndices: DirectiveIndex[],
29-
modeOnHydrate: string, private records: ProtoRecord[],
29+
strategy: string, private records: ProtoRecord[],
3030
private eventBindings: EventBinding[], private directiveRecords: DirectiveRecord[],
3131
private genConfig: ChangeDetectorGenConfig) {
3232
super(id, dispatcher, numberOfPropertyProtoRecords, propertyBindingTargets, directiveIndices,
33-
modeOnHydrate);
33+
strategy);
3434
var len = records.length + 1;
3535
this.values = ListWrapper.createFixedSize(len);
3636
this.localPipes = ListWrapper.createFixedSize(len);
@@ -87,6 +87,13 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
8787
hydrateDirectives(directives: any): void {
8888
this.values[0] = this.context;
8989
this.directives = directives;
90+
91+
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
92+
for (var i = 0; i < this.directiveIndices.length; ++i) {
93+
var index = this.directiveIndices[i];
94+
super.observeDirective(directives.getDirectiveFor(index), i);
95+
}
96+
}
9097
}
9198

9299
dehydrateDirectives(destroyPipes: boolean) {
@@ -211,7 +218,11 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
211218
return null;
212219
}
213220

214-
var currValue = this.observe(this._calculateCurrValue(proto, values, locals), proto.selfIndex);
221+
var currValue = this._calculateCurrValue(proto, values, locals);
222+
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
223+
super.observeValue(currValue, proto.selfIndex);
224+
}
225+
215226
if (proto.shouldBeChecked()) {
216227
var prevValue = this._readSelf(proto, values);
217228
if (!isSame(prevValue, currValue)) {

modules/angular2/src/change_detection/proto_change_detector.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ export class DynamicProtoChangeDetector implements ProtoChangeDetector {
5252
instantiate(dispatcher: any): ChangeDetector {
5353
return new DynamicChangeDetector(
5454
this.definition.id, dispatcher, this._propertyBindingRecords.length,
55-
this._propertyBindingTargets, this._directiveIndices,
56-
ChangeDetectionUtil.changeDetectionMode(this.definition.strategy),
55+
this._propertyBindingTargets, this._directiveIndices, this.definition.strategy,
5756
this._propertyBindingRecords, this._eventBindingRecords, this.definition.directiveRecords,
5857
this.definition.genConfig);
5958
}

modules/angular2/src/transform/template_compiler/change_detector_codegen.dart

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:angular2/src/change_detection/proto_change_detector.dart';
1010
import 'package:angular2/src/change_detection/proto_record.dart';
1111
import 'package:angular2/src/change_detection/event_binding.dart';
1212
import 'package:angular2/src/change_detection/binding_record.dart';
13+
import 'package:angular2/src/change_detection/codegen_facade.dart' show codify;
1314
import 'package:angular2/src/facade/lang.dart' show BaseException;
1415

1516
/// Responsible for generating change detector classes for Angular 2.
@@ -74,7 +75,7 @@ class _CodegenState {
7475
/// The name of the generated change detector class. This is an implementation
7576
/// detail and should not be visible to users.
7677
final String _changeDetectorTypeName;
77-
final String _changeDetectionMode;
78+
final String _changeDetectionStrategy;
7879
final List<DirectiveRecord> _directiveRecords;
7980
final List<ProtoRecord> _records;
8081
final List<EventBinding> _eventBindings;
@@ -87,16 +88,14 @@ class _CodegenState {
8788
this._changeDetectorDefId,
8889
this._contextTypeName,
8990
this._changeDetectorTypeName,
90-
String changeDetectionStrategy,
91+
this._changeDetectionStrategy,
9192
this._records,
9293
this._propertyBindingTargets,
9394
this._eventBindings,
9495
this._directiveRecords,
9596
this._logic,
9697
this._names,
97-
this._genConfig)
98-
: _changeDetectionMode =
99-
ChangeDetectionUtil.changeDetectionMode(changeDetectionStrategy);
98+
this._genConfig);
10099

101100
factory _CodegenState(String typeName, String changeDetectorTypeName,
102101
ChangeDetectorDefinition def) {
@@ -130,7 +129,7 @@ class _CodegenState {
130129
dispatcher, ${_records.length},
131130
${_changeDetectorTypeName}.gen_propertyBindingTargets,
132131
${_changeDetectorTypeName}.gen_directiveIndices,
133-
'$_changeDetectionMode') {
132+
${codify(_changeDetectionStrategy)}) {
134133
dehydrateDirectives(false);
135134
}
136135
@@ -248,7 +247,7 @@ class _CodegenState {
248247
}
249248

250249
String _maybeGenHydrateDirectives() {
251-
var hydrateDirectivesCode = _genHydrateDirectives();
250+
var hydrateDirectivesCode = _logic.genHydrateDirectives(_directiveRecords);
252251
var hydrateDetectorsCode = _logic.genHydrateDetectors(_directiveRecords);
253252
if (hydrateDirectivesCode.isEmpty && hydrateDetectorsCode.isEmpty) {
254253
return '';
@@ -257,16 +256,6 @@ class _CodegenState {
257256
'{ $hydrateDirectivesCode $hydrateDetectorsCode }';
258257
}
259258

260-
String _genHydrateDirectives() {
261-
var buf = new StringBuffer();
262-
var directiveFieldNames = _names.getAllDirectiveNames();
263-
for (var i = 0; i < directiveFieldNames.length; ++i) {
264-
buf.writeln('${directiveFieldNames[i]} = directives.getDirectiveFor('
265-
'${_names.getDirectivesAccessorName()}[$i]);');
266-
}
267-
return '$buf';
268-
}
269-
270259
/// Generates calls to `onAllChangesDone` for all `Directive`s that request
271260
/// them.
272261
String _maybeGenCallOnAllChangesDone() {

0 commit comments

Comments
 (0)
X Tutup