.then((layoutController) => { const layoutView = layoutController.view; ShadowDOM.distributeView(viewPortController.view, layoutController.slots || layoutView.slots); // when there is a layout // view hierarchy is: <router-view/> owner view -> layout view -> ViewPortComponent view layoutController.automate(createOverrideContext(layoutInstruction.viewModel), this.owningView); layoutView.children.push(viewPortController.view); return layoutView || layoutController; })
/** * Used to automate the proper binding of this controller and its view. Used by the composition engine for dynamic component creation. * This should be considered a semi-private API and is subject to change without notice, even across minor or patch releases. * @param overrideContext An override context for binding. * @param owningView The view inside which this controller resides. */ automate(overrideContext?: Object, owningView?: View): void { this.view.bindingContext = this.viewModel; this.view.overrideContext = overrideContext || createOverrideContext(this.viewModel); this.view._isUserControlled = true; if (this.behavior.handlesCreated) { this.viewModel.created(owningView || null, this.view); } this.bind(this.view); }
export function createFullOverrideContext(repeat, data, index, length, key) { let bindingContext = {}; let overrideContext = createOverrideContext(bindingContext, repeat.scope.overrideContext); if (typeof key !== 'undefined') { bindingContext[repeat.key] = key; bindingContext[repeat.value] = data; } else { bindingContext[repeat.local] = data; } updateOverrideContext(overrideContext, index, length); return overrideContext; }
/** * Binds the view and it's children. * @param bindingContext The binding context to bind to. * @param overrideContext A secondary binding context that can override the standard context. */ bind(bindingContext: Object, overrideContext?: Object, _systemUpdate?: boolean): void { let controllers; let bindings; let children; let i; let ii; if (_systemUpdate && this._isUserControlled) { return; } if (this.isBound) { if (this.bindingContext === bindingContext) { return; } this.unbind(); } this.isBound = true; this.bindingContext = bindingContext; this.overrideContext = overrideContext || createOverrideContext(bindingContext); this.resources._invokeHook('beforeBind', this); bindings = this.bindings; for (i = 0, ii = bindings.length; i < ii; ++i) { bindings[i].bind(this); } if (this.viewModelScope !== null) { bindingContext.bind(this.viewModelScope.bindingContext, this.viewModelScope.overrideContext); this.viewModelScope = null; } controllers = this.controllers; for (i = 0, ii = controllers.length; i < ii; ++i) { controllers[i].bind(this); } children = this.children; for (i = 0, ii = children.length; i < ii; ++i) { children[i].bind(bindingContext, overrideContext, true); } if (this.hasSlots) { ShadowDOM.distributeView(this.contentView, this.slots); } }
it('passes bindingContext and overrideContext to .bind()', () => { let bindingContext = { some: 'var' }; let overrideContext = createOverrideContext(bindingContext); overrideContext.foo = 'bar'; let view = templatingEngine.enhance({ element: element, bindingContext: bindingContext, overrideContext: overrideContext }); expect(view.bindingContext).toBe(bindingContext); expect(view.overrideContext).toBe(overrideContext); expect(view.bindingContext.some).toBe('var'); expect(view.overrideContext.foo).toBe('bar'); });
/** * Binds the controller to the scope. * @param scope The binding scope. */ bind(scope: Object): void { let skipSelfSubscriber = this.behavior.handlesBind; let boundProperties = this.boundProperties; let i; let ii; let x; let observer; let selfSubscriber; if (this.isBound) { if (this.scope === scope) { return; } this.unbind(); } this.isBound = true; this.scope = scope; for (i = 0, ii = boundProperties.length; i < ii; ++i) { x = boundProperties[i]; observer = x.observer; selfSubscriber = observer.selfSubscriber; observer.publishing = false; if (skipSelfSubscriber) { observer.selfSubscriber = null; } x.binding.bind(scope); observer.call(); observer.publishing = true; observer.selfSubscriber = selfSubscriber; } let overrideContext; if (this.view !== null) { if (skipSelfSubscriber) { this.view.viewModelScope = scope; } // do we need to create an overrideContext or is the scope's overrideContext // valid for this viewModel? if (this.viewModel === scope.overrideContext.bindingContext) { overrideContext = scope.overrideContext; // should we inherit the parent scope? (eg compose / router) } else if (this.instruction.inheritBindingContext) { overrideContext = createOverrideContext(this.viewModel, scope.overrideContext); // create the overrideContext and capture the parent without making it // available to AccessScope. We may need it later for template-part replacements. } else { overrideContext = createOverrideContext(this.viewModel); overrideContext.__parentOverrideContext = scope.overrideContext; } this.view.bind(this.viewModel, overrideContext); } else if (skipSelfSubscriber) { overrideContext = scope.overrideContext; // the factoryCreateInstruction's partReplacements will either be null or an object // containing the replacements. If there are partReplacements we need to preserve the parent // context to allow replacement parts to bind to both the custom element scope and the ambient scope. // Note that factoryCreateInstruction is a property defined on BoundViewFactory. The code below assumes the // behavior stores a the BoundViewFactory on its viewModel under the name of viewFactory. This is implemented // by the replaceable custom attribute. if (scope.overrideContext.__parentOverrideContext !== undefined && this.viewModel.viewFactory && this.viewModel.viewFactory.factoryCreateInstruction.partReplacements) { // clone the overrideContext and connect the ambient context. overrideContext = Object.assign({}, scope.overrideContext); overrideContext.parentOverrideContext = scope.overrideContext.__parentOverrideContext; } this.viewModel.bind(scope.bindingContext, overrideContext); } }
return this.compositionEngine.createController(layoutInstruction).then(function (controller) { ShadowDOM.distributeView(viewPortInstruction.controller.view, controller.slots || controller.view.slots); controller.automate(createOverrideContext(layoutInstruction.viewModel), _this2.owningView); controller.view.children.push(viewPortInstruction.controller.view); return controller.view || controller; }).then(function (newView) {
beforeEach(() => { repeat = new Repeat(new ViewFactoryMock(), instructionMock, viewSlot, viewResourcesMock, new ObserverLocator()); let bindingContext = {}; repeat.scope = { bindingContext, overrideContext: createOverrideContext(bindingContext) }; viewSlot.children = []; });