feat(change_detection): added support for observable components and directives
This commit is contained in:
parent
85ec34d1d9
commit
e8e430e630
|
@ -15,6 +15,8 @@ import {Locals} from './parser/locals';
|
|||
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from './constants';
|
||||
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
||||
import {isObservable} from './observable_facade';
|
||||
import {ON_PUSH_OBSERVE} from './constants';
|
||||
|
||||
|
||||
var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
|
||||
|
||||
|
@ -44,7 +46,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
|||
|
||||
constructor(public id: string, public dispatcher: ChangeDispatcher,
|
||||
public numberOfPropertyProtoRecords: number, public bindingTargets: BindingTarget[],
|
||||
public directiveIndices: DirectiveIndex[], public modeOnHydrate: string) {
|
||||
public directiveIndices: DirectiveIndex[], public strategy: string) {
|
||||
this.ref = new ChangeDetectorRef(this);
|
||||
}
|
||||
|
||||
|
@ -116,8 +118,13 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
|||
// This method is not intended to be overridden. Subclasses should instead provide an
|
||||
// implementation of `hydrateDirectives`.
|
||||
hydrate(context: T, locals: Locals, directives: any, pipes: any): void {
|
||||
this.mode = this.modeOnHydrate;
|
||||
this.mode = ChangeDetectionUtil.changeDetectionMode(this.strategy);
|
||||
this.context = context;
|
||||
|
||||
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
|
||||
this.observeComponent(context);
|
||||
}
|
||||
|
||||
this.locals = locals;
|
||||
this.pipes = pipes;
|
||||
this.hydrateDirectives(directives);
|
||||
|
@ -133,7 +140,9 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
|||
this.dehydrateDirectives(true);
|
||||
|
||||
// This is an experimental feature. Works only in Dart.
|
||||
this.unsubsribeFromObservables();
|
||||
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
|
||||
this._unsubsribeFromObservables();
|
||||
}
|
||||
|
||||
this.context = null;
|
||||
this.locals = null;
|
||||
|
@ -172,7 +181,8 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
|||
}
|
||||
}
|
||||
|
||||
private unsubsribeFromObservables(): void {
|
||||
// This is an experimental feature. Works only in Dart.
|
||||
private _unsubsribeFromObservables(): void {
|
||||
if (isPresent(this.subscriptions)) {
|
||||
for (var i = 0; i < this.subscriptions.length; ++i) {
|
||||
var s = this.subscriptions[i];
|
||||
|
@ -185,12 +195,9 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
|||
}
|
||||
|
||||
// This is an experimental feature. Works only in Dart.
|
||||
protected observe(value: any, index: number): any {
|
||||
protected observeValue(value: any, index: number): any {
|
||||
if (isObservable(value)) {
|
||||
if (isBlank(this.subscriptions)) {
|
||||
this.subscriptions = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords + 1);
|
||||
this.streams = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords + 1);
|
||||
}
|
||||
this._createArrayToStoreObservables();
|
||||
if (isBlank(this.subscriptions[index])) {
|
||||
this.streams[index] = value.changes;
|
||||
this.subscriptions[index] = value.changes.listen((_) => this.ref.requestCheck());
|
||||
|
@ -203,6 +210,41 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
|||
return value;
|
||||
}
|
||||
|
||||
// This is an experimental feature. Works only in Dart.
|
||||
protected observeDirective(value: any, index: number): any {
|
||||
if (isObservable(value)) {
|
||||
this._createArrayToStoreObservables();
|
||||
var arrayIndex = this.numberOfPropertyProtoRecords + index + 2; // +1 is component
|
||||
this.streams[arrayIndex] = value.changes;
|
||||
this.subscriptions[arrayIndex] = value.changes.listen((_) => this.ref.requestCheck());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// This is an experimental feature. Works only in Dart.
|
||||
protected observeComponent(value: any): any {
|
||||
if (isObservable(value)) {
|
||||
this._createArrayToStoreObservables();
|
||||
var index = this.numberOfPropertyProtoRecords + 1;
|
||||
this.streams[index] = value.changes;
|
||||
this.subscriptions[index] = value.changes.listen((_) => this.ref.requestCheck());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private _createArrayToStoreObservables(): void {
|
||||
if (isBlank(this.subscriptions)) {
|
||||
this.subscriptions = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords +
|
||||
this.directiveIndices.length + 2);
|
||||
this.streams = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords +
|
||||
this.directiveIndices.length + 2);
|
||||
}
|
||||
}
|
||||
|
||||
protected getDirectiveFor(directives: any, index: number): any {
|
||||
return directives.getDirectiveFor(this.directiveIndices[index]);
|
||||
}
|
||||
|
||||
protected getDetectorFor(directives: any, index: number): ChangeDetector {
|
||||
return directives.getDetectorFor(this.directiveIndices[index]);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import {DirectiveIndex, DirectiveRecord} from './directive_record';
|
|||
import {ProtoRecord, RecordType} from './proto_record';
|
||||
import {CodegenNameUtil, sanitizeName} from './codegen_name_util';
|
||||
import {CodegenLogicUtil} from './codegen_logic_util';
|
||||
import {codify} from './codegen_facade';
|
||||
import {EventBinding} from './event_binding';
|
||||
import {BindingTarget} from './binding_record';
|
||||
import {ChangeDetectorGenConfig} from './interfaces';
|
||||
|
@ -48,7 +49,7 @@ export class ChangeDetectorJITGenerator {
|
|||
${ABSTRACT_CHANGE_DETECTOR}.call(
|
||||
this, ${JSON.stringify(this.id)}, dispatcher, ${this.records.length},
|
||||
${this._typeName}.gen_propertyBindingTargets, ${this._typeName}.gen_directiveIndices,
|
||||
"${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}");
|
||||
${codify(this.changeDetectionStrategy)});
|
||||
this.dehydrateDirectives(false);
|
||||
}
|
||||
|
||||
|
@ -160,7 +161,7 @@ export class ChangeDetectorJITGenerator {
|
|||
}
|
||||
|
||||
_maybeGenHydrateDirectives(): string {
|
||||
var hydrateDirectivesCode = this._genHydrateDirectives();
|
||||
var hydrateDirectivesCode = this._logic.genHydrateDirectives(this.directiveRecords);
|
||||
var hydrateDetectorsCode = this._logic.genHydrateDetectors(this.directiveRecords);
|
||||
if (!hydrateDirectivesCode && !hydrateDetectorsCode) return '';
|
||||
return `${this._typeName}.prototype.hydrateDirectives = function(directives) {
|
||||
|
@ -169,16 +170,6 @@ export class ChangeDetectorJITGenerator {
|
|||
}`;
|
||||
}
|
||||
|
||||
_genHydrateDirectives(): string {
|
||||
var directiveFieldNames = this._names.getAllDirectiveNames();
|
||||
var lines = ListWrapper.createFixedSize(directiveFieldNames.length);
|
||||
for (var i = 0, iLen = directiveFieldNames.length; i < iLen; ++i) {
|
||||
lines[i] = `${directiveFieldNames[i]} = directives.getDirectiveFor(
|
||||
${this._names.getDirectivesAccessorName()}[${i}]);`;
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
_maybeGenCallOnAllChangesDone(): string {
|
||||
var notifications = [];
|
||||
var dirs = this.directiveRecords;
|
||||
|
|
|
@ -5,11 +5,7 @@ import {codify, combineGeneratedStrings, rawString} from './codegen_facade';
|
|||
import {ProtoRecord, RecordType} from './proto_record';
|
||||
import {BindingTarget} from './binding_record';
|
||||
import {DirectiveRecord} from './directive_record';
|
||||
|
||||
/**
|
||||
* This is an experimental feature. Works only in Dart.
|
||||
*/
|
||||
const ON_PUSH_OBSERVE = "ON_PUSH_OBSERVE";
|
||||
import {ON_PUSH_OBSERVE} from './constants';
|
||||
|
||||
/**
|
||||
* Class responsible for providing change detection logic for chagne detector classes.
|
||||
|
@ -118,7 +114,7 @@ export class CodegenLogicUtil {
|
|||
_observe(exp: string, rec: ProtoRecord): string {
|
||||
// This is an experimental feature. Works only in Dart.
|
||||
if (StringWrapper.equals(this._changeDetection, ON_PUSH_OBSERVE)) {
|
||||
return `this.observe(${exp}, ${rec.selfIndex})`;
|
||||
return `this.observeValue(${exp}, ${rec.selfIndex})`;
|
||||
} else {
|
||||
return exp;
|
||||
}
|
||||
|
@ -152,6 +148,24 @@ export class CodegenLogicUtil {
|
|||
return combineGeneratedStrings(iVals);
|
||||
}
|
||||
|
||||
genHydrateDirectives(directiveRecords: DirectiveRecord[]): string {
|
||||
var res = [];
|
||||
for (var i = 0; i < directiveRecords.length; ++i) {
|
||||
var r = directiveRecords[i];
|
||||
res.push(`${this._names.getDirectiveName(r.directiveIndex)} = ${this._genReadDirective(i)};`);
|
||||
}
|
||||
return res.join("\n");
|
||||
}
|
||||
|
||||
private _genReadDirective(index: number) {
|
||||
// This is an experimental feature. Works only in Dart.
|
||||
if (StringWrapper.equals(this._changeDetection, ON_PUSH_OBSERVE)) {
|
||||
return `this.observeDirective(this.getDirectiveFor(directives, ${index}), ${index})`;
|
||||
} else {
|
||||
return `this.getDirectiveFor(directives, ${index})`;
|
||||
}
|
||||
}
|
||||
|
||||
genHydrateDetectors(directiveRecords: DirectiveRecord[]): string {
|
||||
var res = [];
|
||||
for (var i = 0; i < directiveRecords.length; ++i) {
|
||||
|
|
|
@ -190,10 +190,6 @@ export class CodegenNameUtil {
|
|||
return this._addFieldPrefix(`${this._sanitizedNames[idx]}_pipe`);
|
||||
}
|
||||
|
||||
getAllDirectiveNames(): List<string> {
|
||||
return ListWrapper.map(this.directiveRecords, d => this.getDirectiveName(d.directiveIndex));
|
||||
}
|
||||
|
||||
getDirectiveName(d: DirectiveIndex): string {
|
||||
return this._addFieldPrefix(`directive_${d.name}`);
|
||||
}
|
||||
|
|
|
@ -37,4 +37,10 @@ export const DEFAULT: string = "DEFAULT";
|
|||
|
||||
export function isDefaultChangeDetectionStrategy(changeDetectionStrategy: string): boolean {
|
||||
return isBlank(changeDetectionStrategy) || StringWrapper.equals(changeDetectionStrategy, DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is an experimental feature. Works only in Dart.
|
||||
*/
|
||||
export const ON_PUSH_OBSERVE = "ON_PUSH_OBSERVE";
|
|
@ -14,7 +14,7 @@ import {DirectiveRecord, DirectiveIndex} from './directive_record';
|
|||
import {Locals} from './parser/locals';
|
||||
import {ChangeDetectorGenConfig} from './interfaces';
|
||||
import {ChangeDetectionUtil, SimpleChange} from './change_detection_util';
|
||||
|
||||
import {ON_PUSH_OBSERVE} from './constants';
|
||||
import {ProtoRecord, RecordType} from './proto_record';
|
||||
|
||||
export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||
|
@ -26,11 +26,11 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
|||
|
||||
constructor(id: string, dispatcher: any, numberOfPropertyProtoRecords: number,
|
||||
propertyBindingTargets: BindingTarget[], directiveIndices: DirectiveIndex[],
|
||||
modeOnHydrate: string, private records: ProtoRecord[],
|
||||
strategy: string, private records: ProtoRecord[],
|
||||
private eventBindings: EventBinding[], private directiveRecords: DirectiveRecord[],
|
||||
private genConfig: ChangeDetectorGenConfig) {
|
||||
super(id, dispatcher, numberOfPropertyProtoRecords, propertyBindingTargets, directiveIndices,
|
||||
modeOnHydrate);
|
||||
strategy);
|
||||
var len = records.length + 1;
|
||||
this.values = ListWrapper.createFixedSize(len);
|
||||
this.localPipes = ListWrapper.createFixedSize(len);
|
||||
|
@ -87,6 +87,13 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
|||
hydrateDirectives(directives: any): void {
|
||||
this.values[0] = this.context;
|
||||
this.directives = directives;
|
||||
|
||||
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
|
||||
for (var i = 0; i < this.directiveIndices.length; ++i) {
|
||||
var index = this.directiveIndices[i];
|
||||
super.observeDirective(directives.getDirectiveFor(index), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dehydrateDirectives(destroyPipes: boolean) {
|
||||
|
@ -211,7 +218,11 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
|||
return null;
|
||||
}
|
||||
|
||||
var currValue = this.observe(this._calculateCurrValue(proto, values, locals), proto.selfIndex);
|
||||
var currValue = this._calculateCurrValue(proto, values, locals);
|
||||
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
|
||||
super.observeValue(currValue, proto.selfIndex);
|
||||
}
|
||||
|
||||
if (proto.shouldBeChecked()) {
|
||||
var prevValue = this._readSelf(proto, values);
|
||||
if (!isSame(prevValue, currValue)) {
|
||||
|
|
|
@ -52,8 +52,7 @@ export class DynamicProtoChangeDetector implements ProtoChangeDetector {
|
|||
instantiate(dispatcher: any): ChangeDetector {
|
||||
return new DynamicChangeDetector(
|
||||
this.definition.id, dispatcher, this._propertyBindingRecords.length,
|
||||
this._propertyBindingTargets, this._directiveIndices,
|
||||
ChangeDetectionUtil.changeDetectionMode(this.definition.strategy),
|
||||
this._propertyBindingTargets, this._directiveIndices, this.definition.strategy,
|
||||
this._propertyBindingRecords, this._eventBindingRecords, this.definition.directiveRecords,
|
||||
this.definition.genConfig);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:angular2/src/change_detection/proto_change_detector.dart';
|
|||
import 'package:angular2/src/change_detection/proto_record.dart';
|
||||
import 'package:angular2/src/change_detection/event_binding.dart';
|
||||
import 'package:angular2/src/change_detection/binding_record.dart';
|
||||
import 'package:angular2/src/change_detection/codegen_facade.dart' show codify;
|
||||
import 'package:angular2/src/facade/lang.dart' show BaseException;
|
||||
|
||||
/// Responsible for generating change detector classes for Angular 2.
|
||||
|
@ -74,7 +75,7 @@ class _CodegenState {
|
|||
/// The name of the generated change detector class. This is an implementation
|
||||
/// detail and should not be visible to users.
|
||||
final String _changeDetectorTypeName;
|
||||
final String _changeDetectionMode;
|
||||
final String _changeDetectionStrategy;
|
||||
final List<DirectiveRecord> _directiveRecords;
|
||||
final List<ProtoRecord> _records;
|
||||
final List<EventBinding> _eventBindings;
|
||||
|
@ -87,16 +88,14 @@ class _CodegenState {
|
|||
this._changeDetectorDefId,
|
||||
this._contextTypeName,
|
||||
this._changeDetectorTypeName,
|
||||
String changeDetectionStrategy,
|
||||
this._changeDetectionStrategy,
|
||||
this._records,
|
||||
this._propertyBindingTargets,
|
||||
this._eventBindings,
|
||||
this._directiveRecords,
|
||||
this._logic,
|
||||
this._names,
|
||||
this._genConfig)
|
||||
: _changeDetectionMode =
|
||||
ChangeDetectionUtil.changeDetectionMode(changeDetectionStrategy);
|
||||
this._genConfig);
|
||||
|
||||
factory _CodegenState(String typeName, String changeDetectorTypeName,
|
||||
ChangeDetectorDefinition def) {
|
||||
|
@ -130,7 +129,7 @@ class _CodegenState {
|
|||
dispatcher, ${_records.length},
|
||||
${_changeDetectorTypeName}.gen_propertyBindingTargets,
|
||||
${_changeDetectorTypeName}.gen_directiveIndices,
|
||||
'$_changeDetectionMode') {
|
||||
${codify(_changeDetectionStrategy)}) {
|
||||
dehydrateDirectives(false);
|
||||
}
|
||||
|
||||
|
@ -248,7 +247,7 @@ class _CodegenState {
|
|||
}
|
||||
|
||||
String _maybeGenHydrateDirectives() {
|
||||
var hydrateDirectivesCode = _genHydrateDirectives();
|
||||
var hydrateDirectivesCode = _logic.genHydrateDirectives(_directiveRecords);
|
||||
var hydrateDetectorsCode = _logic.genHydrateDetectors(_directiveRecords);
|
||||
if (hydrateDirectivesCode.isEmpty && hydrateDetectorsCode.isEmpty) {
|
||||
return '';
|
||||
|
@ -257,16 +256,6 @@ class _CodegenState {
|
|||
'{ $hydrateDirectivesCode $hydrateDetectorsCode }';
|
||||
}
|
||||
|
||||
String _genHydrateDirectives() {
|
||||
var buf = new StringBuffer();
|
||||
var directiveFieldNames = _names.getAllDirectiveNames();
|
||||
for (var i = 0; i < directiveFieldNames.length; ++i) {
|
||||
buf.writeln('${directiveFieldNames[i]} = directives.getDirectiveFor('
|
||||
'${_names.getDirectivesAccessorName()}[$i]);');
|
||||
}
|
||||
return '$buf';
|
||||
}
|
||||
|
||||
/// Generates calls to `onAllChangesDone` for all `Directive`s that request
|
||||
/// them.
|
||||
String _maybeGenCallOnAllChangesDone() {
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
Parser,
|
||||
ChangeDetectorGenConfig
|
||||
} from 'angular2/src/change_detection/change_detection';
|
||||
import {ON_PUSH_OBSERVE} from 'angular2/src/change_detection/constants';
|
||||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities';
|
||||
|
||||
|
@ -106,11 +107,19 @@ export function getDefinition(id: string): TestDefinition {
|
|||
[_DirectiveUpdating.basicRecords[0]], genConfig);
|
||||
testDef = new TestDefinition(id, cdDef, null);
|
||||
|
||||
} else if (id == "onPushObserve") {
|
||||
} else if (id == "onPushObserveBinding") {
|
||||
var records = _createBindingRecords("a");
|
||||
let cdDef = new ChangeDetectorDefinition(id, "ON_PUSH_OBSERVE", [], records, [], [], genConfig);
|
||||
let cdDef = new ChangeDetectorDefinition(id, ON_PUSH_OBSERVE, [], records, [], [], genConfig);
|
||||
testDef = new TestDefinition(id, cdDef, null);
|
||||
|
||||
} else if (id == "onPushObserveComponent") {
|
||||
let cdDef = new ChangeDetectorDefinition(id, ON_PUSH_OBSERVE, [], [], [], [], genConfig);
|
||||
testDef = new TestDefinition(id, cdDef, null);
|
||||
|
||||
} else if (id == "onPushObserveDirective") {
|
||||
let cdDef = new ChangeDetectorDefinition(id, ON_PUSH_OBSERVE, [], [], [],
|
||||
[_DirectiveUpdating.recordNoCallbacks], genConfig);
|
||||
testDef = new TestDefinition(id, cdDef, null);
|
||||
} else if (id == "updateElementProduction") {
|
||||
var genConfig = new ChangeDetectorGenConfig(false, false, false);
|
||||
var records = _createBindingRecords("name");
|
||||
|
@ -118,7 +127,6 @@ export function getDefinition(id: string): TestDefinition {
|
|||
testDef = new TestDefinition(id, cdDef, null);
|
||||
}
|
||||
|
||||
|
||||
if (isBlank(testDef)) {
|
||||
throw `No ChangeDetectorDefinition for ${id} available. Please modify this file if necessary.`;
|
||||
}
|
||||
|
@ -144,7 +152,12 @@ export function getAllDefinitions(): List<TestDefinition> {
|
|||
ListWrapper.concat(allDefs, StringMapWrapper.keys(_DirectiveUpdating.availableDefinitions));
|
||||
allDefs = ListWrapper.concat(allDefs, _availableEventDefinitions);
|
||||
allDefs = ListWrapper.concat(allDefs, _availableHostEventDefinitions);
|
||||
allDefs = ListWrapper.concat(allDefs, ["onPushObserve", "updateElementProduction"]);
|
||||
allDefs = ListWrapper.concat(allDefs, [
|
||||
"onPushObserveBinding",
|
||||
"onPushObserveComponent",
|
||||
"onPushObserveDirective",
|
||||
"updateElementProduction"
|
||||
]);
|
||||
return ListWrapper.map(allDefs, (id) => getDefinition(id));
|
||||
}
|
||||
|
||||
|
|
|
@ -781,64 +781,100 @@ export function main() {
|
|||
});
|
||||
|
||||
if (IS_DART) {
|
||||
it('should mark ON_PUSH_OBSERVE detectors as CHECK_ONCE when an observable fires an event',
|
||||
fakeAsync(() => {
|
||||
var context = new TestDirective();
|
||||
context.a = createObservableModel();
|
||||
describe('ON_PUSH_OBSERVE', () => {
|
||||
it('should mark ON_PUSH_OBSERVE detectors as CHECK_ONCE when an observable fires an event',
|
||||
fakeAsync(() => {
|
||||
var context = new TestDirective();
|
||||
context.a = createObservableModel();
|
||||
|
||||
var cd = _createWithoutHydrate('onPushObserve').changeDetector;
|
||||
cd.hydrate(context, null, directives, null);
|
||||
cd.detectChanges();
|
||||
var cd = _createWithoutHydrate('onPushObserveBinding').changeDetector;
|
||||
cd.hydrate(context, null, directives, null);
|
||||
cd.detectChanges();
|
||||
|
||||
expect(cd.mode).toEqual(CHECKED);
|
||||
expect(cd.mode).toEqual(CHECKED);
|
||||
|
||||
context.a.pushUpdate();
|
||||
tick();
|
||||
context.a.pushUpdate();
|
||||
tick();
|
||||
|
||||
expect(cd.mode).toEqual(CHECK_ONCE);
|
||||
}));
|
||||
expect(cd.mode).toEqual(CHECK_ONCE);
|
||||
}));
|
||||
|
||||
it('should unsubscribe from an old observable when an object changes', fakeAsync(() => {
|
||||
var originalModel = createObservableModel();
|
||||
var context = new TestDirective();
|
||||
context.a = originalModel;
|
||||
it('should mark ON_PUSH_OBSERVE detectors as CHECK_ONCE when an observable context fires an event',
|
||||
fakeAsync(() => {
|
||||
var context = createObservableModel();
|
||||
|
||||
var cd = _createWithoutHydrate('onPushObserve').changeDetector;
|
||||
cd.hydrate(context, null, directives, null);
|
||||
cd.detectChanges();
|
||||
var cd = _createWithoutHydrate('onPushObserveComponent').changeDetector;
|
||||
cd.hydrate(context, null, directives, null);
|
||||
cd.detectChanges();
|
||||
|
||||
context.a = createObservableModel();
|
||||
cd.mode = CHECK_ONCE;
|
||||
cd.detectChanges();
|
||||
expect(cd.mode).toEqual(CHECKED);
|
||||
|
||||
// Updating this model will not reenable the detector. This model is not longer
|
||||
// used.
|
||||
originalModel.pushUpdate();
|
||||
tick();
|
||||
expect(cd.mode).toEqual(CHECKED);
|
||||
}));
|
||||
context.pushUpdate();
|
||||
tick();
|
||||
|
||||
it('should unsubscribe from observables when dehydrating', fakeAsync(() => {
|
||||
var originalModel = createObservableModel();
|
||||
var context = new TestDirective();
|
||||
context.a = originalModel;
|
||||
expect(cd.mode).toEqual(CHECK_ONCE);
|
||||
}));
|
||||
|
||||
var cd = _createWithoutHydrate('onPushObserve').changeDetector;
|
||||
cd.hydrate(context, null, directives, null);
|
||||
cd.detectChanges();
|
||||
it('should mark ON_PUSH_OBSERVE detectors as CHECK_ONCE when an observable directive fires an event',
|
||||
fakeAsync(() => {
|
||||
var dir = createObservableModel();
|
||||
var directives = new FakeDirectives([dir], []);
|
||||
|
||||
cd.dehydrate();
|
||||
var cd = _createWithoutHydrate('onPushObserveDirective').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, directives, null);
|
||||
cd.detectChanges();
|
||||
|
||||
context.a = "not an observable model";
|
||||
cd.hydrate(context, null, directives, null);
|
||||
cd.detectChanges();
|
||||
expect(cd.mode).toEqual(CHECKED);
|
||||
|
||||
// Updating this model will not reenable the detector. This model is not longer
|
||||
// used.
|
||||
originalModel.pushUpdate();
|
||||
tick();
|
||||
expect(cd.mode).toEqual(CHECKED);
|
||||
}));
|
||||
dir.pushUpdate();
|
||||
tick();
|
||||
|
||||
expect(cd.mode).toEqual(CHECK_ONCE);
|
||||
}));
|
||||
|
||||
it('should unsubscribe from an old observable when an object changes',
|
||||
fakeAsync(() => {
|
||||
var originalModel = createObservableModel();
|
||||
var context = new TestDirective();
|
||||
context.a = originalModel;
|
||||
|
||||
var cd = _createWithoutHydrate('onPushObserveBinding').changeDetector;
|
||||
cd.hydrate(context, null, directives, null);
|
||||
cd.detectChanges();
|
||||
|
||||
context.a = createObservableModel();
|
||||
cd.mode = CHECK_ONCE;
|
||||
cd.detectChanges();
|
||||
|
||||
// Updating this model will not reenable the detector. This model is not longer
|
||||
// used.
|
||||
originalModel.pushUpdate();
|
||||
tick();
|
||||
expect(cd.mode).toEqual(CHECKED);
|
||||
}));
|
||||
|
||||
it('should unsubscribe from observables when dehydrating', fakeAsync(() => {
|
||||
var originalModel = createObservableModel();
|
||||
var context = new TestDirective();
|
||||
context.a = originalModel;
|
||||
|
||||
var cd = _createWithoutHydrate('onPushObserveBinding').changeDetector;
|
||||
cd.hydrate(context, null, directives, null);
|
||||
cd.detectChanges();
|
||||
|
||||
cd.dehydrate();
|
||||
|
||||
context.a = "not an observable model";
|
||||
cd.hydrate(context, null, directives, null);
|
||||
cd.detectChanges();
|
||||
|
||||
// Updating this model will not reenable the detector. This model is not longer
|
||||
// used.
|
||||
originalModel.pushUpdate();
|
||||
tick();
|
||||
expect(cd.mode).toEqual(CHECKED);
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -29,7 +29,7 @@ class _MyComponent_ChangeDetector0
|
|||
_MyComponent_ChangeDetector0(dispatcher) : super(
|
||||
"MyComponent_comp_0", dispatcher, 2,
|
||||
_MyComponent_ChangeDetector0.gen_propertyBindingTargets,
|
||||
_MyComponent_ChangeDetector0.gen_directiveIndices, 'ALWAYS_CHECK') {
|
||||
_MyComponent_ChangeDetector0.gen_directiveIndices,null) {
|
||||
dehydrateDirectives(false);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue