UNPKG

angular2

Version:

Angular 2 - a web framework for modern web apps

274 lines 14.5 kB
'use strict';var lang_1 = require('angular2/src/facade/lang'); var collection_1 = require('angular2/src/facade/collection'); var change_detection_util_1 = require('./change_detection_util'); var change_detector_ref_1 = require('./change_detector_ref'); var exceptions_1 = require('./exceptions'); var constants_1 = require('./constants'); var profile_1 = require('../profile/profile'); var observable_facade_1 = require('./observable_facade'); var _scope_check = profile_1.wtfCreateScope("ChangeDetector#check(ascii id, bool throwOnChange)"); var _Context = (function () { function _Context(element, componentElement, context, locals, injector, expression) { this.element = element; this.componentElement = componentElement; this.context = context; this.locals = locals; this.injector = injector; this.expression = expression; } return _Context; })(); var AbstractChangeDetector = (function () { function AbstractChangeDetector(id, dispatcher, numberOfPropertyProtoRecords, bindingTargets, directiveIndices, strategy) { this.id = id; this.dispatcher = dispatcher; this.numberOfPropertyProtoRecords = numberOfPropertyProtoRecords; this.bindingTargets = bindingTargets; this.directiveIndices = directiveIndices; this.strategy = strategy; this.contentChildren = []; this.viewChildren = []; // The names of the below fields must be kept in sync with codegen_name_util.ts or // change detection will fail. this.state = constants_1.ChangeDetectorState.NeverChecked; this.locals = null; this.mode = null; this.pipes = null; this.ref = new change_detector_ref_1.ChangeDetectorRef_(this); } AbstractChangeDetector.prototype.addContentChild = function (cd) { this.contentChildren.push(cd); cd.parent = this; }; AbstractChangeDetector.prototype.removeContentChild = function (cd) { collection_1.ListWrapper.remove(this.contentChildren, cd); }; AbstractChangeDetector.prototype.addViewChild = function (cd) { this.viewChildren.push(cd); cd.parent = this; }; AbstractChangeDetector.prototype.removeViewChild = function (cd) { collection_1.ListWrapper.remove(this.viewChildren, cd); }; AbstractChangeDetector.prototype.remove = function () { this.parent.removeContentChild(this); }; AbstractChangeDetector.prototype.handleEvent = function (eventName, elIndex, locals) { var res = this.handleEventInternal(eventName, elIndex, locals); this.markPathToRootAsCheckOnce(); return res; }; AbstractChangeDetector.prototype.handleEventInternal = function (eventName, elIndex, locals) { return false; }; AbstractChangeDetector.prototype.detectChanges = function () { this.runDetectChanges(false); }; AbstractChangeDetector.prototype.checkNoChanges = function () { if (lang_1.assertionsEnabled()) { this.runDetectChanges(true); } }; AbstractChangeDetector.prototype.runDetectChanges = function (throwOnChange) { if (this.mode === constants_1.ChangeDetectionStrategy.Detached || this.mode === constants_1.ChangeDetectionStrategy.Checked || this.state === constants_1.ChangeDetectorState.Errored) return; var s = _scope_check(this.id, throwOnChange); this.detectChangesInRecords(throwOnChange); this._detectChangesContentChildren(throwOnChange); if (!throwOnChange) this.afterContentLifecycleCallbacks(); this._detectChangesInViewChildren(throwOnChange); if (!throwOnChange) this.afterViewLifecycleCallbacks(); if (this.mode === constants_1.ChangeDetectionStrategy.CheckOnce) this.mode = constants_1.ChangeDetectionStrategy.Checked; this.state = constants_1.ChangeDetectorState.CheckedBefore; profile_1.wtfLeave(s); }; // This method is not intended to be overridden. Subclasses should instead provide an // implementation of `detectChangesInRecordsInternal` which does the work of detecting changes // and which this method will call. // This method expects that `detectChangesInRecordsInternal` will set the property // `this.propertyBindingIndex` to the propertyBindingIndex of the first proto record. This is to // facilitate error reporting. AbstractChangeDetector.prototype.detectChangesInRecords = function (throwOnChange) { if (!this.hydrated()) { this.throwDehydratedError(); } try { this.detectChangesInRecordsInternal(throwOnChange); } catch (e) { // throwOnChange errors aren't counted as fatal errors. if (!(e instanceof exceptions_1.ExpressionChangedAfterItHasBeenCheckedException)) { this.state = constants_1.ChangeDetectorState.Errored; } this._throwError(e, e.stack); } }; // Subclasses should override this method to perform any work necessary to detect and report // changes. For example, changes should be reported via `ChangeDetectionUtil.addChange`, lifecycle // methods should be called, etc. // This implementation should also set `this.propertyBindingIndex` to the propertyBindingIndex of // the // first proto record to facilitate error reporting. See {@link #detectChangesInRecords}. AbstractChangeDetector.prototype.detectChangesInRecordsInternal = function (throwOnChange) { }; // This method is not intended to be overridden. Subclasses should instead provide an // implementation of `hydrateDirectives`. AbstractChangeDetector.prototype.hydrate = function (context, locals, directives, pipes) { this.mode = change_detection_util_1.ChangeDetectionUtil.changeDetectionMode(this.strategy); this.context = context; if (this.strategy === constants_1.ChangeDetectionStrategy.OnPushObserve) { this.observeComponent(context); } this.locals = locals; this.pipes = pipes; this.hydrateDirectives(directives); this.state = constants_1.ChangeDetectorState.NeverChecked; }; // Subclasses should override this method to hydrate any directives. AbstractChangeDetector.prototype.hydrateDirectives = function (directives) { }; // This method is not intended to be overridden. Subclasses should instead provide an // implementation of `dehydrateDirectives`. AbstractChangeDetector.prototype.dehydrate = function () { this.dehydrateDirectives(true); // This is an experimental feature. Works only in Dart. if (this.strategy === constants_1.ChangeDetectionStrategy.OnPushObserve) { this._unsubsribeFromObservables(); } this.context = null; this.locals = null; this.pipes = null; }; // Subclasses should override this method to dehydrate any directives. This method should reverse // any work done in `hydrateDirectives`. AbstractChangeDetector.prototype.dehydrateDirectives = function (destroyPipes) { }; AbstractChangeDetector.prototype.hydrated = function () { return this.context !== null; }; AbstractChangeDetector.prototype.afterContentLifecycleCallbacks = function () { this.dispatcher.notifyAfterContentChecked(); this.afterContentLifecycleCallbacksInternal(); }; AbstractChangeDetector.prototype.afterContentLifecycleCallbacksInternal = function () { }; AbstractChangeDetector.prototype.afterViewLifecycleCallbacks = function () { this.dispatcher.notifyAfterViewChecked(); this.afterViewLifecycleCallbacksInternal(); }; AbstractChangeDetector.prototype.afterViewLifecycleCallbacksInternal = function () { }; /** @internal */ AbstractChangeDetector.prototype._detectChangesContentChildren = function (throwOnChange) { var c = this.contentChildren; for (var i = 0; i < c.length; ++i) { c[i].runDetectChanges(throwOnChange); } }; /** @internal */ AbstractChangeDetector.prototype._detectChangesInViewChildren = function (throwOnChange) { var c = this.viewChildren; for (var i = 0; i < c.length; ++i) { c[i].runDetectChanges(throwOnChange); } }; AbstractChangeDetector.prototype.markAsCheckOnce = function () { this.mode = constants_1.ChangeDetectionStrategy.CheckOnce; }; AbstractChangeDetector.prototype.markPathToRootAsCheckOnce = function () { var c = this; while (lang_1.isPresent(c) && c.mode !== constants_1.ChangeDetectionStrategy.Detached) { if (c.mode === constants_1.ChangeDetectionStrategy.Checked) c.mode = constants_1.ChangeDetectionStrategy.CheckOnce; c = c.parent; } }; // This is an experimental feature. Works only in Dart. AbstractChangeDetector.prototype._unsubsribeFromObservables = function () { if (lang_1.isPresent(this.subscriptions)) { for (var i = 0; i < this.subscriptions.length; ++i) { var s = this.subscriptions[i]; if (lang_1.isPresent(this.subscriptions[i])) { s.cancel(); this.subscriptions[i] = null; } } } }; // This is an experimental feature. Works only in Dart. AbstractChangeDetector.prototype.observeValue = function (value, index) { var _this = this; if (observable_facade_1.isObservable(value)) { this._createArrayToStoreObservables(); if (lang_1.isBlank(this.subscriptions[index])) { this.streams[index] = value.changes; this.subscriptions[index] = value.changes.listen(function (_) { return _this.ref.markForCheck(); }); } else if (this.streams[index] !== value.changes) { this.subscriptions[index].cancel(); this.streams[index] = value.changes; this.subscriptions[index] = value.changes.listen(function (_) { return _this.ref.markForCheck(); }); } } return value; }; // This is an experimental feature. Works only in Dart. AbstractChangeDetector.prototype.observeDirective = function (value, index) { var _this = this; if (observable_facade_1.isObservable(value)) { this._createArrayToStoreObservables(); var arrayIndex = this.numberOfPropertyProtoRecords + index + 2; // +1 is component this.streams[arrayIndex] = value.changes; this.subscriptions[arrayIndex] = value.changes.listen(function (_) { return _this.ref.markForCheck(); }); } return value; }; // This is an experimental feature. Works only in Dart. AbstractChangeDetector.prototype.observeComponent = function (value) { var _this = this; if (observable_facade_1.isObservable(value)) { this._createArrayToStoreObservables(); var index = this.numberOfPropertyProtoRecords + 1; this.streams[index] = value.changes; this.subscriptions[index] = value.changes.listen(function (_) { return _this.ref.markForCheck(); }); } return value; }; AbstractChangeDetector.prototype._createArrayToStoreObservables = function () { if (lang_1.isBlank(this.subscriptions)) { this.subscriptions = collection_1.ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords + this.directiveIndices.length + 2); this.streams = collection_1.ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords + this.directiveIndices.length + 2); } }; AbstractChangeDetector.prototype.getDirectiveFor = function (directives, index) { return directives.getDirectiveFor(this.directiveIndices[index]); }; AbstractChangeDetector.prototype.getDetectorFor = function (directives, index) { return directives.getDetectorFor(this.directiveIndices[index]); }; AbstractChangeDetector.prototype.notifyDispatcher = function (value) { this.dispatcher.notifyOnBinding(this._currentBinding(), value); }; AbstractChangeDetector.prototype.logBindingUpdate = function (value) { this.dispatcher.logBindingUpdate(this._currentBinding(), value); }; AbstractChangeDetector.prototype.addChange = function (changes, oldValue, newValue) { if (lang_1.isBlank(changes)) { changes = {}; } changes[this._currentBinding().name] = change_detection_util_1.ChangeDetectionUtil.simpleChange(oldValue, newValue); return changes; }; AbstractChangeDetector.prototype._throwError = function (exception, stack) { var error; try { var c = this.dispatcher.getDebugContext(this._currentBinding().elementIndex, null); var context = lang_1.isPresent(c) ? new _Context(c.element, c.componentElement, c.context, c.locals, c.injector, this._currentBinding().debug) : null; error = new exceptions_1.ChangeDetectionError(this._currentBinding().debug, exception, stack, context); } catch (e) { // if an error happens during getting the debug context, we throw a ChangeDetectionError // without the extra information. error = new exceptions_1.ChangeDetectionError(null, exception, stack, null); } throw error; }; AbstractChangeDetector.prototype.throwOnChangeError = function (oldValue, newValue) { throw new exceptions_1.ExpressionChangedAfterItHasBeenCheckedException(this._currentBinding().debug, oldValue, newValue, null); }; AbstractChangeDetector.prototype.throwDehydratedError = function () { throw new exceptions_1.DehydratedException(); }; AbstractChangeDetector.prototype._currentBinding = function () { return this.bindingTargets[this.propertyBindingIndex]; }; return AbstractChangeDetector; })(); exports.AbstractChangeDetector = AbstractChangeDetector; //# sourceMappingURL=abstract_change_detector.js.map