Compare commits
3 Commits
merge_pr_m
...
6.0.0-beta
Author | SHA1 | Date | |
---|---|---|---|
e751a0a2bb | |||
288851c41e | |||
9eaf1bbe67 |
70
CHANGELOG.md
70
CHANGELOG.md
@ -1,3 +1,73 @@
|
||||
<a name="6.0.0-beta.5"></a>
|
||||
# [6.0.0-beta.5](https://github.com/angular/angular/compare/6.0.0-beta.4...6.0.0-beta.5) (2018-02-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** only use the WA-polyfill alongside AnimationBuilder ([#22143](https://github.com/angular/angular/issues/22143)) ([b2f366b](https://github.com/angular/angular/commit/b2f366b)), closes [#17496](https://github.com/angular/angular/issues/17496)
|
||||
* **animations:** report correct totalTime value even during noOp animations ([#22225](https://github.com/angular/angular/issues/22225)) ([e1bf067](https://github.com/angular/angular/commit/e1bf067))
|
||||
* **bazel:** ng_package includes transitive .d.ts and flatModuleMetadata ([#22499](https://github.com/angular/angular/issues/22499)) ([aabe16c](https://github.com/angular/angular/commit/aabe16c)), closes [#22419](https://github.com/angular/angular/issues/22419)
|
||||
* **common:** correct mapping of Observable methods ([#20518](https://github.com/angular/angular/issues/20518)) ([2639b4b](https://github.com/angular/angular/commit/2639b4b)), closes [#20516](https://github.com/angular/angular/issues/20516)
|
||||
* **common:** then and else template might be set to null ([#22298](https://github.com/angular/angular/issues/22298)) ([8115edc](https://github.com/angular/angular/commit/8115edc))
|
||||
* **compiler-cli:** add missing entry point to package, update tsickle ([#22295](https://github.com/angular/angular/issues/22295)) ([28ac244](https://github.com/angular/angular/commit/28ac244))
|
||||
* **core:** export inject() from [@angular](https://github.com/angular)/core ([#22389](https://github.com/angular/angular/issues/22389)) ([f8749bf](https://github.com/angular/angular/commit/f8749bf)), closes [#22388](https://github.com/angular/angular/issues/22388)
|
||||
* **core:** properly handle function without prototype in reflector ([#22284](https://github.com/angular/angular/issues/22284)) ([a7ebf5a](https://github.com/angular/angular/commit/a7ebf5a)), closes [#19978](https://github.com/angular/angular/issues/19978)
|
||||
* **core:** require factory to be provided for shakeable InjectionToken ([#22207](https://github.com/angular/angular/issues/22207)) ([f755db7](https://github.com/angular/angular/commit/f755db7)), closes [#22205](https://github.com/angular/angular/issues/22205)
|
||||
* **forms:** set state before emitting a value from ngModelChange ([#21514](https://github.com/angular/angular/issues/21514)) ([3e6a86f](https://github.com/angular/angular/commit/3e6a86f)), closes [#21513](https://github.com/angular/angular/issues/21513)
|
||||
* **platform-server:** generate correct stylings for camel case names ([#22263](https://github.com/angular/angular/issues/22263)) ([40ba009](https://github.com/angular/angular/commit/40ba009)), closes [#19235](https://github.com/angular/angular/issues/19235)
|
||||
* **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([45eff4c](https://github.com/angular/angular/commit/45eff4c)), closes [#22203](https://github.com/angular/angular/issues/22203)
|
||||
* **router:** fix URL serialization so special characters are only encoded where needed ([#22337](https://github.com/angular/angular/issues/22337)) ([094666d](https://github.com/angular/angular/commit/094666d)), closes [#10280](https://github.com/angular/angular/issues/10280)
|
||||
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([8a85888](https://github.com/angular/angular/commit/8a85888)), closes [#22392](https://github.com/angular/angular/issues/22392)
|
||||
* **upgrade:** correctly handle `=` bindings in `[@angular](https://github.com/angular)/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([f089bf5](https://github.com/angular/angular/commit/f089bf5))
|
||||
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([13ab91e](https://github.com/angular/angular/commit/13ab91e)), closes [#22175](https://github.com/angular/angular/issues/22175)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **bazel:** add an ng_package rule ([#22221](https://github.com/angular/angular/issues/22221)) ([b43b164](https://github.com/angular/angular/commit/b43b164))
|
||||
* **bazel:** introduce a binary stamping feature ([#22176](https://github.com/angular/angular/issues/22176)) ([bba65e0](https://github.com/angular/angular/commit/bba65e0))
|
||||
* **bazel:** ng_module produces bundle index ([#22176](https://github.com/angular/angular/issues/22176)) ([029dbf0](https://github.com/angular/angular/commit/029dbf0))
|
||||
* **bazel:** ng_package adds package.json props ([#22499](https://github.com/angular/angular/issues/22499)) ([b6c9410](https://github.com/angular/angular/commit/b6c9410)), closes [#22416](https://github.com/angular/angular/issues/22416)
|
||||
* **common:** better error message when non-template element used in NgIf ([#22274](https://github.com/angular/angular/issues/22274)) ([67cf11d](https://github.com/angular/angular/commit/67cf11d)), closes [#16410](https://github.com/angular/angular/issues/16410)
|
||||
* **common:** export functions to format numbers, percents, currencies & dates ([#22423](https://github.com/angular/angular/issues/22423)) ([4180912](https://github.com/angular/angular/commit/4180912)), closes [#20536](https://github.com/angular/angular/issues/20536)
|
||||
* **compiler-cli:** Check unvalidated combination of ngc and TypeScript ([#22293](https://github.com/angular/angular/issues/22293)) ([3ceee99](https://github.com/angular/angular/commit/3ceee99)), closes [#20669](https://github.com/angular/angular/issues/20669)
|
||||
* **core:** set preserveWhitespaces to false by default ([#22046](https://github.com/angular/angular/issues/22046)) ([f1a0632](https://github.com/angular/angular/commit/f1a0632)), closes [#22027](https://github.com/angular/angular/issues/22027)
|
||||
* **core:** support metadata reflection for native class types ([#22356](https://github.com/angular/angular/issues/22356)) ([5c89d6b](https://github.com/angular/angular/commit/5c89d6b)), closes [#21731](https://github.com/angular/angular/issues/21731)
|
||||
* **core:** support metadata reflection for native class types ([#22356](https://github.com/angular/angular/issues/22356)) ([b7544cc](https://github.com/angular/angular/commit/b7544cc)), closes [#21731](https://github.com/angular/angular/issues/21731)
|
||||
* **forms:** allow markAsPending to emit events ([#20212](https://github.com/angular/angular/issues/20212)) ([e86b64b](https://github.com/angular/angular/commit/e86b64b)), closes [#17958](https://github.com/angular/angular/issues/17958)
|
||||
* allow direct scoping of @Injectables to the root injector ([#22185](https://github.com/angular/angular/issues/22185)) ([7ac34e4](https://github.com/angular/angular/commit/7ac34e4))
|
||||
* **platform-browser:** do not throw error when Hammer.js not loaded ([#22257](https://github.com/angular/angular/issues/22257)) ([991300b](https://github.com/angular/angular/commit/991300b)), closes [#16992](https://github.com/angular/angular/issues/16992)
|
||||
* **platform-browser:** fix [#19604](https://github.com/angular/angular/issues/19604), can config hammerOptions ([#21979](https://github.com/angular/angular/issues/21979)) ([1d571b2](https://github.com/angular/angular/commit/1d571b2))
|
||||
* **platform-server:** bump Domino to v2.0 ([#22411](https://github.com/angular/angular/issues/22411)) ([d3827a0](https://github.com/angular/angular/commit/d3827a0))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* **platform-server:** * Bump the dependency on Domino to 2.0 to resolve issues with
|
||||
namespacing
|
||||
* **forms:** - `AbstractControl#statusChanges` now emits an event of `'PENDING'` when you call `AbstractControl#markAsPending`
|
||||
- Previously it did not emit an event when you called `markAsPending`
|
||||
- To migrate you would need to ensure that if you are filtering or checking events from `statusChanges` that you account for the new event when calling `markAsPending`
|
||||
* **animations:** When animation is trigged within a disabled zone, the
|
||||
associated event (which an instance of AnimationEvent) will no longer
|
||||
report the totalTime as 0 (it will emit the actual time of the
|
||||
animation). To detect if an animation event is reporting a disabled
|
||||
animation then the `event.disabled` property can be used instead.
|
||||
|
||||
|
||||
|
||||
<a name="5.2.7"></a>
|
||||
## [5.2.7](https://github.com/angular/angular/compare/5.2.6...5.2.7) (2018-02-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **platform-server:** generate correct stylings for camel case names ([#22263](https://github.com/angular/angular/issues/22263)) ([de02a7a](https://github.com/angular/angular/commit/de02a7a)), closes [#19235](https://github.com/angular/angular/issues/19235)
|
||||
* **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203)
|
||||
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392)
|
||||
* **upgrade:** correctly handle `=` bindings in `[@angular](https://github.com/angular)/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390))
|
||||
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175)
|
||||
|
||||
<a name="6.0.0-beta.5"></a>
|
||||
# [6.0.0-beta.5](https://github.com/angular/angular/compare/6.0.0-beta.4...6.0.0-beta.5) (2018-02-22)
|
||||
|
||||
|
8
build.sh
8
build.sh
@ -33,6 +33,11 @@ TSC_PACKAGES=(compiler-cli
|
||||
NODE_PACKAGES=(compiler-cli
|
||||
benchpress)
|
||||
|
||||
NG_UPDATE_PACKAGE_GROUP=$(
|
||||
echo \[\"${PACKAGES[@]}\"] | sed 's/ /", "/g'
|
||||
)
|
||||
|
||||
|
||||
BUILD_ALL=true
|
||||
BUNDLE=true
|
||||
VERSION_PREFIX=$(node -p "require('./package.json').version")
|
||||
@ -491,6 +496,9 @@ do
|
||||
rsync -am --include="package.json" --include="*/" --exclude=* ${SRC_DIR}/ ${NPM_DIR}/
|
||||
rsync -am --include="*.externs.js" --include="*/" --exclude=* ${SRC_DIR}/ ${NPM_DIR}/
|
||||
|
||||
# Replace the NG_UPDATE_PACKAGE_GROUP value with the JSON array of packages.
|
||||
perl -p -i -e "s/\"NG_UPDATE_PACKAGE_GROUP\"/${NG_UPDATE_PACKAGE_GROUP}/g" ${NPM_DIR}/package.json < /dev/null 2> /dev/null
|
||||
|
||||
cp ${ROOT_DIR}/README.md ${NPM_DIR}/
|
||||
fi
|
||||
|
||||
|
@ -17,5 +17,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -19,5 +19,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -34,5 +34,8 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/angular/angular/issues"
|
||||
},
|
||||
"homepage": "https://github.com/angular/angular/tree/master/packages/compiler-cli"
|
||||
"homepage": "https://github.com/angular/angular/tree/master/packages/compiler-cli",
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -14,5 +14,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -18,5 +18,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ export {
|
||||
inject as ɵinject,
|
||||
injectTemplateRef as ɵinjectTemplateRef,
|
||||
injectViewContainerRef as ɵinjectViewContainerRef,
|
||||
injectChangeDetectorRef as ɵinjectChangeDetectorRef,
|
||||
InjectFlags as ɵInjectFlags,
|
||||
PublicFeature as ɵPublicFeature,
|
||||
NgOnChangesFeature as ɵNgOnChangesFeature,
|
||||
|
@ -10,16 +10,14 @@
|
||||
// correctly implementing its interfaces for backwards compatibility.
|
||||
import {Injector} from '../di/injector';
|
||||
import {ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
|
||||
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef} from '../linker/view_ref';
|
||||
|
||||
import {assertNotNull} from './assert';
|
||||
import {CLEAN_PROMISE, NG_HOST_SYMBOL, _getComponentHostLElementNode, createError, createLView, createTView, detectChanges, directiveCreate, enterView, getDirectiveInstance, hostElement, leaveView, locateHostElement, scheduleChangeDetection} from './instructions';
|
||||
import {CLEAN_PROMISE, _getComponentHostLElementNode, createLView, createTView, detectChanges, directiveCreate, enterView, getDirectiveInstance, hostElement, initChangeDetectorIfExisting, leaveView, locateHostElement, scheduleChangeDetection} from './instructions';
|
||||
import {ComponentDef, ComponentType} from './interfaces/definition';
|
||||
import {LElementNode} from './interfaces/node';
|
||||
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||
import {LViewFlags, RootContext} from './interfaces/view';
|
||||
import {notImplemented, stringify} from './util';
|
||||
|
||||
import {stringify} from './util';
|
||||
import {createViewRef} from './view_ref';
|
||||
|
||||
|
||||
/** Options that control how the component should be bootstrapped. */
|
||||
@ -69,7 +67,7 @@ export interface CreateComponentOptions {
|
||||
export function createComponentRef<T>(
|
||||
componentType: ComponentType<T>, opts: CreateComponentOptions): viewEngine_ComponentRef<T> {
|
||||
const component = renderComponent(componentType, opts);
|
||||
const hostView = createViewRef(() => detectChanges(component), component);
|
||||
const hostView = createViewRef(component);
|
||||
return {
|
||||
location: {nativeElement: getHostElement(component)},
|
||||
injector: opts.injector || NULL_INJECTOR,
|
||||
@ -83,84 +81,6 @@ export function createComponentRef<T>(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an EmbeddedViewRef.
|
||||
*
|
||||
* @param detectChanges The detectChanges function for this view
|
||||
* @param context The context for this view
|
||||
* @returns The EmbeddedViewRef
|
||||
*/
|
||||
function createViewRef<T>(detectChanges: () => void, context: T): EmbeddedViewRef<T> {
|
||||
return addDestroyable(new EmbeddedViewRef(detectChanges), context);
|
||||
}
|
||||
|
||||
class EmbeddedViewRef<T> implements viewEngine_EmbeddedViewRef<T> {
|
||||
// TODO: rootNodes should be replaced when properly implemented
|
||||
rootNodes = null !;
|
||||
context: T;
|
||||
destroyed: boolean;
|
||||
|
||||
constructor(public detectChanges: () => void) {}
|
||||
|
||||
// inherited from core/ChangeDetectorRef
|
||||
markForCheck() {
|
||||
if (ngDevMode) {
|
||||
throw notImplemented();
|
||||
}
|
||||
}
|
||||
detach() {
|
||||
if (ngDevMode) {
|
||||
throw notImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
checkNoChanges() {
|
||||
if (ngDevMode) {
|
||||
throw notImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
reattach() {
|
||||
if (ngDevMode) {
|
||||
throw notImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
destroy(): void {}
|
||||
|
||||
onDestroy(cb: Function): void {}
|
||||
}
|
||||
|
||||
/** Interface for destroy logic. Implemented by addDestroyable. */
|
||||
interface DestroyRef<T> {
|
||||
context: T;
|
||||
/** Whether or not this object has been destroyed */
|
||||
destroyed: boolean;
|
||||
/** Destroy the instance and call all onDestroy callbacks. */
|
||||
destroy(): void;
|
||||
/** Register callbacks that should be called onDestroy */
|
||||
onDestroy(cb: Function): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorates an object with destroy logic (implementing the DestroyRef interface)
|
||||
* and returns the enhanced object.
|
||||
*
|
||||
* @param obj The object to decorate
|
||||
* @returns The object with destroy logic
|
||||
*/
|
||||
function addDestroyable<T, C>(obj: any, context: C): T&DestroyRef<C> {
|
||||
let destroyFn: Function[]|null = null;
|
||||
obj.destroyed = false;
|
||||
obj.destroy = function() {
|
||||
destroyFn && destroyFn.forEach((fn) => fn());
|
||||
this.destroyed = true;
|
||||
};
|
||||
obj.onDestroy = (fn: Function) => (destroyFn || (destroyFn = [])).push(fn);
|
||||
obj.context = context;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
// TODO: A hack to not pull in the NullInjector from @angular/core.
|
||||
export const NULL_INJECTOR: Injector = {
|
||||
@ -202,10 +122,12 @@ export function renderComponent<T>(
|
||||
null !);
|
||||
try {
|
||||
// Create element node at index 0 in data array
|
||||
hostElement(hostNode, componentDef);
|
||||
const elementNode = hostElement(hostNode, componentDef);
|
||||
// Create directive instance with n() and store at index 1 in data array (el is 0)
|
||||
const instance = componentDef.n();
|
||||
component = rootContext.component =
|
||||
getDirectiveInstance(directiveCreate(1, componentDef.n(), componentDef));
|
||||
getDirectiveInstance(directiveCreate(1, instance, componentDef));
|
||||
initChangeDetectorIfExisting(elementNode.nodeInjector, instance);
|
||||
} finally {
|
||||
leaveView(oldView);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
// We are temporarily importing the existing viewEngine_from core so we can be sure we are
|
||||
// correctly implementing its interfaces for backwards compatibility.
|
||||
import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
||||
import {Injector} from '../di/injector';
|
||||
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
|
||||
import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref';
|
||||
@ -24,10 +25,10 @@ import {LInjector} from './interfaces/injector';
|
||||
import {LContainerNode, LElementNode, LNode, LNodeFlags, LViewNode} from './interfaces/node';
|
||||
import {QueryReadType} from './interfaces/query';
|
||||
import {Renderer3} from './interfaces/renderer';
|
||||
import {LView} from './interfaces/view';
|
||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||
import {insertView} from './node_manipulation';
|
||||
import {notImplemented, stringify} from './util';
|
||||
import {EmbeddedViewRef, ViewRef, addDestroyable, createViewRef} from './view_ref';
|
||||
|
||||
|
||||
|
||||
@ -124,7 +125,8 @@ export function getOrCreateNodeInjectorForNode(node: LElementNode | LContainerNo
|
||||
injector: null,
|
||||
templateRef: null,
|
||||
viewContainerRef: null,
|
||||
elementRef: null
|
||||
elementRef: null,
|
||||
changeDetectorRef: null
|
||||
};
|
||||
}
|
||||
|
||||
@ -227,6 +229,55 @@ export function injectViewContainerRef(): viewEngine_ViewContainerRef {
|
||||
return getOrCreateContainerRef(getOrCreateNodeInjector());
|
||||
}
|
||||
|
||||
/** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */
|
||||
export function injectChangeDetectorRef(): viewEngine_ChangeDetectorRef {
|
||||
return getOrCreateChangeDetectorRef(getOrCreateNodeInjector(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ViewRef and stores it on the injector as ChangeDetectorRef (public alias).
|
||||
* Or, if it already exists, retrieves the existing instance.
|
||||
*
|
||||
* @returns The ChangeDetectorRef to use
|
||||
*/
|
||||
export function getOrCreateChangeDetectorRef(
|
||||
di: LInjector, context: any): viewEngine_ChangeDetectorRef {
|
||||
if (di.changeDetectorRef) return di.changeDetectorRef;
|
||||
|
||||
const currentNode = di.node;
|
||||
if (currentNode.data === null) {
|
||||
// if data is null, this node is a regular element node (not a component)
|
||||
return di.changeDetectorRef = getOrCreateHostChangeDetector(currentNode.view.node);
|
||||
} else if ((currentNode.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Element) {
|
||||
// if it's an element node with data, it's a component and context will be set later
|
||||
return di.changeDetectorRef = createViewRef(context);
|
||||
}
|
||||
return null !;
|
||||
}
|
||||
|
||||
/** Gets or creates ChangeDetectorRef for the closest host component */
|
||||
function getOrCreateHostChangeDetector(currentNode: LViewNode | LElementNode):
|
||||
viewEngine_ChangeDetectorRef {
|
||||
const hostNode = getClosestComponentAncestor(currentNode);
|
||||
const hostInjector = hostNode.nodeInjector;
|
||||
const existingRef = hostInjector && hostInjector.changeDetectorRef;
|
||||
|
||||
return existingRef ? existingRef :
|
||||
createViewRef(hostNode.view.data[hostNode.flags >> LNodeFlags.INDX_SHIFT]);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the node is an embedded view, traverses up the view tree to return the closest
|
||||
* ancestor view that is attached to a component. If it's already a component node,
|
||||
* returns itself.
|
||||
*/
|
||||
function getClosestComponentAncestor(node: LViewNode | LElementNode): LElementNode {
|
||||
while ((node.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.View) {
|
||||
node = node.view.node;
|
||||
}
|
||||
return node as LElementNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for an instance of the given directive type up the injector tree and returns
|
||||
* that instance if found.
|
||||
@ -527,29 +578,6 @@ class TemplateRef<T> implements viewEngine_TemplateRef<T> {
|
||||
|
||||
createEmbeddedView(context: T): viewEngine_EmbeddedViewRef<T> {
|
||||
let viewNode: LViewNode = renderEmbeddedTemplate(null, this._template, context, this._renderer);
|
||||
return new EmbeddedViewRef(viewNode, this._template, context);
|
||||
return addDestroyable(new EmbeddedViewRef(viewNode, this._template, context));
|
||||
}
|
||||
}
|
||||
|
||||
class EmbeddedViewRef<T> implements viewEngine_EmbeddedViewRef<T> {
|
||||
context: T;
|
||||
rootNodes: any[];
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_lViewNode: LViewNode;
|
||||
|
||||
constructor(viewNode: LViewNode, template: ComponentTemplate<T>, context: T) {
|
||||
this._lViewNode = viewNode;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
destroy(): void { notImplemented(); }
|
||||
destroyed: boolean;
|
||||
onDestroy(callback: Function) { notImplemented(); }
|
||||
markForCheck(): void { notImplemented(); }
|
||||
detach(): void { notImplemented(); }
|
||||
detectChanges(): void { notImplemented(); }
|
||||
checkNoChanges(): void { notImplemented(); }
|
||||
reattach(): void { notImplemented(); }
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import {NgOnChangesFeature, PublicFeature, defineComponent, defineDirective, def
|
||||
import {InjectFlags} from './di';
|
||||
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType} from './interfaces/definition';
|
||||
|
||||
export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, inject, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
|
||||
export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, inject, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
|
||||
export {CssSelector} from './interfaces/projection';
|
||||
|
||||
|
||||
|
@ -10,6 +10,7 @@ import './ng_dev_mode';
|
||||
|
||||
import {assertEqual, assertLessThan, assertNotEqual, assertNotNull, assertNull, assertSame} from './assert';
|
||||
import {LContainer, TContainer} from './interfaces/container';
|
||||
import {LInjector} from './interfaces/injector';
|
||||
import {CssSelector, LProjection} from './interfaces/projection';
|
||||
import {LQueries} from './interfaces/query';
|
||||
import {LView, LViewFlags, LifecycleStage, RootContext, TData, TView} from './interfaces/view';
|
||||
@ -22,6 +23,7 @@ import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveT
|
||||
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
||||
import {isDifferent, stringify} from './util';
|
||||
import {executeHooks, executeContentHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks';
|
||||
import {ViewRef} from './view_ref';
|
||||
|
||||
/**
|
||||
* Directive (D) sets a property on all component instances using this constant as a key and the
|
||||
@ -465,7 +467,9 @@ export function elementStart(
|
||||
if (hostComponentDef) {
|
||||
// TODO(mhevery): This assumes that the directives come in correct order, which
|
||||
// is not guaranteed. Must be refactored to take it into account.
|
||||
directiveCreate(++index, hostComponentDef.n(), hostComponentDef, queryName);
|
||||
const instance = hostComponentDef.n();
|
||||
directiveCreate(++index, instance, hostComponentDef, queryName);
|
||||
initChangeDetectorIfExisting(node.nodeInjector, instance);
|
||||
}
|
||||
hack_declareDirectives(index, directiveTypes, localRefs);
|
||||
}
|
||||
@ -473,6 +477,13 @@ export function elementStart(
|
||||
return native;
|
||||
}
|
||||
|
||||
/** Sets the context for a ChangeDetectorRef to the given instance. */
|
||||
export function initChangeDetectorIfExisting(injector: LInjector | null, instance: any): void {
|
||||
if (injector && injector.changeDetectorRef != null) {
|
||||
(injector.changeDetectorRef as ViewRef<any>)._setComponentContext(instance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function instantiates a directive with a correct queryName. It is a hack since we should
|
||||
* compute the query value only once and store it with the template (rather than on each invocation)
|
||||
@ -589,10 +600,12 @@ export function locateHostElement(
|
||||
*
|
||||
* @param rNode Render host element.
|
||||
* @param def ComponentDef
|
||||
*
|
||||
* @returns LElementNode created
|
||||
*/
|
||||
export function hostElement(rNode: RElement | null, def: ComponentDef<any>) {
|
||||
export function hostElement(rNode: RElement | null, def: ComponentDef<any>): LElementNode {
|
||||
resetApplicationState();
|
||||
createLNode(
|
||||
return createLNode(
|
||||
0, LNodeFlags.Element, rNode, createLView(
|
||||
-1, renderer, getOrCreateTView(def.template), null, null,
|
||||
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways));
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectorRef} from '../../change_detection/change_detector_ref';
|
||||
import {Injector} from '../../di/injector';
|
||||
import {ElementRef} from '../../linker/element_ref';
|
||||
import {TemplateRef} from '../../linker/template_ref';
|
||||
@ -66,6 +67,12 @@ export interface LInjector {
|
||||
|
||||
/** Stores the ElementRef so subsequent injections of the ElementRef get the same instance. */
|
||||
elementRef: ElementRef|null;
|
||||
|
||||
/**
|
||||
* Stores the ChangeDetectorRef so subsequent injections of the ChangeDetectorRef get the
|
||||
* same instance.
|
||||
*/
|
||||
changeDetectorRef: ChangeDetectorRef|null;
|
||||
}
|
||||
|
||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||
|
84
packages/core/src/render3/view_ref.ts
Normal file
84
packages/core/src/render3/view_ref.ts
Normal file
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
|
||||
|
||||
import {ComponentTemplate} from './interfaces/definition';
|
||||
import {LViewNode} from './interfaces/node';
|
||||
import {notImplemented} from './util';
|
||||
|
||||
export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T> {
|
||||
context: T;
|
||||
rootNodes: any[];
|
||||
|
||||
constructor(context: T|null) { this.context = context !; }
|
||||
|
||||
/** @internal */
|
||||
_setComponentContext(context: T) { this.context = context; }
|
||||
|
||||
destroy(): void { notImplemented(); }
|
||||
destroyed: boolean;
|
||||
onDestroy(callback: Function) { notImplemented(); }
|
||||
markForCheck(): void { notImplemented(); }
|
||||
detach(): void { notImplemented(); }
|
||||
detectChanges(): void { notImplemented(); }
|
||||
checkNoChanges(): void { notImplemented(); }
|
||||
reattach(): void { notImplemented(); }
|
||||
}
|
||||
|
||||
|
||||
export class EmbeddedViewRef<T> extends ViewRef<T> {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_lViewNode: LViewNode;
|
||||
|
||||
constructor(viewNode: LViewNode, template: ComponentTemplate<T>, context: T) {
|
||||
super(context);
|
||||
this._lViewNode = viewNode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ViewRef bundled with destroy functionality.
|
||||
*
|
||||
* @param context The context for this view
|
||||
* @returns The ViewRef
|
||||
*/
|
||||
export function createViewRef<T>(context: T): ViewRef<T> {
|
||||
// TODO: add detectChanges back in when implementing ChangeDetectorRef.detectChanges
|
||||
return addDestroyable(new ViewRef(context));
|
||||
}
|
||||
|
||||
/** Interface for destroy logic. Implemented by addDestroyable. */
|
||||
export interface DestroyRef<T> {
|
||||
/** Whether or not this object has been destroyed */
|
||||
destroyed: boolean;
|
||||
/** Destroy the instance and call all onDestroy callbacks. */
|
||||
destroy(): void;
|
||||
/** Register callbacks that should be called onDestroy */
|
||||
onDestroy(cb: Function): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorates an object with destroy logic (implementing the DestroyRef interface)
|
||||
* and returns the enhanced object.
|
||||
*
|
||||
* @param obj The object to decorate
|
||||
* @returns The object with destroy logic
|
||||
*/
|
||||
export function addDestroyable<T, C>(obj: any): T&DestroyRef<C> {
|
||||
let destroyFn: Function[]|null = null;
|
||||
obj.destroyed = false;
|
||||
obj.destroy = function() {
|
||||
destroyFn && destroyFn.forEach((fn) => fn());
|
||||
this.destroyed = true;
|
||||
};
|
||||
obj.onDestroy = (fn: Function) => (destroyFn || (destroyFn = [])).push(fn);
|
||||
return obj;
|
||||
}
|
@ -6,9 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
|
||||
import * as $r3$ from '../../../src/core_render3_private_export';
|
||||
|
||||
import {renderComponent, toHtml} from '../render_util';
|
||||
|
||||
/**
|
||||
@ -1313,6 +1312,52 @@ describe('compiler specification', () => {
|
||||
|
||||
});
|
||||
|
||||
it('should inject ChangeDetectorRef', () => {
|
||||
type $MyComp$ = MyComp;
|
||||
type $MyApp$ = MyApp;
|
||||
|
||||
@Component({selector: 'my-comp', template: `{{ value }}`})
|
||||
class MyComp {
|
||||
value: string;
|
||||
constructor(public cdr: ChangeDetectorRef) { this.value = (cdr.constructor as any).name; }
|
||||
|
||||
// NORMATIVE
|
||||
static ngComponentDef = $r3$.ɵdefineComponent({
|
||||
type: MyComp,
|
||||
tag: 'my-comp',
|
||||
factory: function MyComp_Factory() { return new MyComp($r3$.ɵinjectChangeDetectorRef()); },
|
||||
template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) {
|
||||
if (cm) {
|
||||
$r3$.ɵT(0);
|
||||
}
|
||||
$r3$.ɵt(0, $r3$.ɵb(ctx.value));
|
||||
}
|
||||
});
|
||||
// /NORMATIVE
|
||||
}
|
||||
|
||||
class MyApp {
|
||||
static ngComponentDef = $r3$.ɵdefineComponent({
|
||||
type: MyApp,
|
||||
tag: 'my-app',
|
||||
factory: function MyApp_Factory() { return new MyApp(); },
|
||||
/** <my-comp></my-comp> */
|
||||
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) {
|
||||
if (cm) {
|
||||
$r3$.ɵE(0, MyComp);
|
||||
$r3$.ɵe();
|
||||
}
|
||||
MyComp.ngComponentDef.h(1, 0);
|
||||
$r3$.ɵr(1, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const app = renderComponent(MyApp);
|
||||
// ChangeDetectorRef is the token, ViewRef is historically the constructor
|
||||
expect(toHtml(app)).toEqual('<my-comp>ViewRef</my-comp>');
|
||||
});
|
||||
|
||||
describe('template variables', () => {
|
||||
|
||||
interface ForOfContext {
|
||||
|
@ -6,17 +6,18 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
|
||||
import {ChangeDetectorRef, ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
|
||||
|
||||
import {defineComponent} from '../../src/render3/definition';
|
||||
import {InjectFlags, bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector} from '../../src/render3/di';
|
||||
import {PublicFeature, defineDirective, inject, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
||||
import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLView, createTView, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, load, text, textBinding} from '../../src/render3/instructions';
|
||||
import {NgOnChangesFeature, PublicFeature, defineDirective, inject, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
||||
import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLView, createTView, directiveRefresh, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, load, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
|
||||
import {LInjector} from '../../src/render3/interfaces/injector';
|
||||
import {LNodeFlags} from '../../src/render3/interfaces/node';
|
||||
import {LViewFlags} from '../../src/render3/interfaces/view';
|
||||
import {ViewRef} from '../../src/render3/view_ref';
|
||||
|
||||
import {renderComponent, renderToHtml} from './render_util';
|
||||
import {renderComponent, renderToHtml, toHtml} from './render_util';
|
||||
|
||||
describe('di', () => {
|
||||
describe('no dependencies', () => {
|
||||
@ -199,6 +200,273 @@ describe('di', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('ChangeDetectorRef', () => {
|
||||
let dir: Directive;
|
||||
let dirSameInstance: DirectiveSameInstance;
|
||||
let comp: MyComp;
|
||||
|
||||
class MyComp {
|
||||
constructor(public cdr: ChangeDetectorRef) {}
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyComp,
|
||||
tag: 'my-comp',
|
||||
factory: () => comp = new MyComp(injectChangeDetectorRef()),
|
||||
template: function(ctx: MyComp, cm: boolean) {
|
||||
if (cm) {
|
||||
projectionDef(0);
|
||||
projection(1, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class Directive {
|
||||
value: string;
|
||||
constructor(public cdr: ChangeDetectorRef) { this.value = (cdr.constructor as any).name; }
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: Directive,
|
||||
factory: () => dir = new Directive(injectChangeDetectorRef()),
|
||||
features: [PublicFeature],
|
||||
exportAs: 'dir'
|
||||
});
|
||||
}
|
||||
|
||||
class DirectiveSameInstance {
|
||||
constructor(public cdr: ChangeDetectorRef) {}
|
||||
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: DirectiveSameInstance,
|
||||
factory: () => dirSameInstance = new DirectiveSameInstance(injectChangeDetectorRef())
|
||||
});
|
||||
}
|
||||
|
||||
const $e0_attrs$ = ['dir', '', 'dirSameInstance', ''];
|
||||
|
||||
it('should inject current component ChangeDetectorRef into directives on components', () => {
|
||||
class MyApp {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyApp,
|
||||
tag: 'my-app',
|
||||
factory: () => new MyApp(),
|
||||
/** <my-comp dir dirSameInstance #dir="dir"></my-comp> {{ dir.value }} */
|
||||
template: function(ctx: any, cm: boolean) {
|
||||
if (cm) {
|
||||
elementStart(0, MyComp, $e0_attrs$, [Directive, DirectiveSameInstance]);
|
||||
elementEnd();
|
||||
text(4);
|
||||
}
|
||||
textBinding(4, bind(load<Directive>(2).value));
|
||||
MyComp.ngComponentDef.h(1, 0);
|
||||
Directive.ngDirectiveDef.h(2, 0);
|
||||
DirectiveSameInstance.ngDirectiveDef.h(3, 0);
|
||||
directiveRefresh(1, 0);
|
||||
directiveRefresh(2, 0);
|
||||
directiveRefresh(3, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const app = renderComponent(MyApp);
|
||||
// ChangeDetectorRef is the token, ViewRef has historically been the constructor
|
||||
expect(toHtml(app)).toEqual('<my-comp dir="" dirsameinstance=""></my-comp>ViewRef');
|
||||
expect((comp !.cdr as ViewRef<MyComp>).context).toBe(comp);
|
||||
|
||||
expect(dir !.cdr).toBe(comp !.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
it('should inject host component ChangeDetectorRef into directives on elements', () => {
|
||||
|
||||
class MyApp {
|
||||
constructor(public cdr: ChangeDetectorRef) {}
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyApp,
|
||||
tag: 'my-app',
|
||||
factory: () => new MyApp(injectChangeDetectorRef()),
|
||||
/** <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
|
||||
template: function(ctx: any, cm: boolean) {
|
||||
if (cm) {
|
||||
elementStart(0, 'div', $e0_attrs$, [Directive, DirectiveSameInstance]);
|
||||
{ text(3); }
|
||||
elementEnd();
|
||||
}
|
||||
textBinding(3, bind(load<Directive>(1).value));
|
||||
Directive.ngDirectiveDef.h(1, 0);
|
||||
DirectiveSameInstance.ngDirectiveDef.h(2, 0);
|
||||
directiveRefresh(1, 0);
|
||||
directiveRefresh(2, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const app = renderComponent(MyApp);
|
||||
expect(toHtml(app)).toEqual('<div dir="" dirsameinstance="">ViewRef</div>');
|
||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
||||
|
||||
expect(dir !.cdr).toBe(app.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
it('should inject host component ChangeDetectorRef into directives in ContentChildren', () => {
|
||||
class MyApp {
|
||||
constructor(public cdr: ChangeDetectorRef) {}
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyApp,
|
||||
tag: 'my-app',
|
||||
factory: () => new MyApp(injectChangeDetectorRef()),
|
||||
/**
|
||||
* <my-comp>
|
||||
* <div dir dirSameInstance #dir="dir"></div>
|
||||
* </my-comp>
|
||||
* {{ dir.value }}
|
||||
*/
|
||||
template: function(ctx: any, cm: boolean) {
|
||||
if (cm) {
|
||||
elementStart(0, MyComp);
|
||||
{
|
||||
elementStart(2, 'div', $e0_attrs$, [Directive, DirectiveSameInstance]);
|
||||
elementEnd();
|
||||
}
|
||||
elementEnd();
|
||||
text(5);
|
||||
}
|
||||
textBinding(5, bind(load<Directive>(3).value));
|
||||
MyComp.ngComponentDef.h(1, 0);
|
||||
Directive.ngDirectiveDef.h(3, 2);
|
||||
DirectiveSameInstance.ngDirectiveDef.h(4, 2);
|
||||
directiveRefresh(1, 0);
|
||||
directiveRefresh(3, 2);
|
||||
directiveRefresh(4, 2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const app = renderComponent(MyApp);
|
||||
expect(toHtml(app))
|
||||
.toEqual('<my-comp><div dir="" dirsameinstance=""></div></my-comp>ViewRef');
|
||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
||||
|
||||
expect(dir !.cdr).toBe(app !.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
it('should inject host component ChangeDetectorRef into directives in embedded views', () => {
|
||||
|
||||
class MyApp {
|
||||
showing = true;
|
||||
|
||||
constructor(public cdr: ChangeDetectorRef) {}
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyApp,
|
||||
tag: 'my-app',
|
||||
factory: () => new MyApp(injectChangeDetectorRef()),
|
||||
/**
|
||||
* % if (showing) {
|
||||
* <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div>
|
||||
* % }
|
||||
*/
|
||||
template: function(ctx: MyApp, cm: boolean) {
|
||||
if (cm) {
|
||||
container(0);
|
||||
}
|
||||
containerRefreshStart(0);
|
||||
{
|
||||
if (ctx.showing) {
|
||||
if (embeddedViewStart(0)) {
|
||||
elementStart(0, 'div', $e0_attrs$, [Directive, DirectiveSameInstance]);
|
||||
{ text(3); }
|
||||
elementEnd();
|
||||
}
|
||||
textBinding(3, bind(load<Directive>(1).value));
|
||||
Directive.ngDirectiveDef.h(1, 0);
|
||||
DirectiveSameInstance.ngDirectiveDef.h(2, 0);
|
||||
directiveRefresh(1, 0);
|
||||
directiveRefresh(2, 0);
|
||||
}
|
||||
embeddedViewEnd();
|
||||
}
|
||||
containerRefreshEnd();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const app = renderComponent(MyApp);
|
||||
expect(toHtml(app)).toEqual('<div dir="" dirsameinstance="">ViewRef</div>');
|
||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
||||
|
||||
expect(dir !.cdr).toBe(app.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
it('should inject host component ChangeDetectorRef into directives on containers', () => {
|
||||
class IfDirective {
|
||||
/* @Input */
|
||||
myIf = true;
|
||||
|
||||
constructor(public template: TemplateRef<any>, public vcr: ViewContainerRef) {}
|
||||
|
||||
ngOnChanges() {
|
||||
if (this.myIf) {
|
||||
this.vcr.createEmbeddedView(this.template);
|
||||
}
|
||||
}
|
||||
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: IfDirective,
|
||||
factory: () => new IfDirective(injectTemplateRef(), injectViewContainerRef()),
|
||||
inputs: {myIf: 'myIf'},
|
||||
features: [PublicFeature, NgOnChangesFeature]
|
||||
});
|
||||
}
|
||||
|
||||
class MyApp {
|
||||
showing = true;
|
||||
|
||||
constructor(public cdr: ChangeDetectorRef) {}
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyApp,
|
||||
tag: 'my-app',
|
||||
factory: () => new MyApp(injectChangeDetectorRef()),
|
||||
/** <div *myIf="showing" dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
|
||||
template: function(ctx: MyApp, cm: boolean) {
|
||||
if (cm) {
|
||||
container(0, [IfDirective], C1);
|
||||
}
|
||||
containerRefreshStart(0);
|
||||
{ directiveRefresh(1, 0); }
|
||||
containerRefreshEnd();
|
||||
|
||||
function C1(ctx1: any, cm1: boolean) {
|
||||
if (cm1) {
|
||||
elementStart(0, 'div', $e0_attrs$, [Directive, DirectiveSameInstance]);
|
||||
{ text(3); }
|
||||
elementEnd();
|
||||
}
|
||||
textBinding(3, bind(load<Directive>(1).value));
|
||||
Directive.ngDirectiveDef.h(1, 0);
|
||||
DirectiveSameInstance.ngDirectiveDef.h(2, 0);
|
||||
directiveRefresh(1, 0);
|
||||
directiveRefresh(2, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const app = renderComponent(MyApp);
|
||||
expect(toHtml(app)).toEqual('<div dir="" dirsameinstance="">ViewRef</div>');
|
||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
||||
|
||||
expect(dir !.cdr).toBe(app.cdr);
|
||||
expect(dir !.cdr).toBe(dirSameInstance !.cdr);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('inject', () => {
|
||||
describe('bloom filter', () => {
|
||||
let di: LInjector;
|
||||
|
@ -20,5 +20,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -19,5 +19,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -10,5 +10,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -20,5 +20,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -18,5 +18,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -24,5 +24,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -21,5 +21,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -19,5 +19,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -28,5 +28,8 @@
|
||||
"@angular/common": "0.0.0-PLACEHOLDER",
|
||||
"@angular/platform-browser": "0.0.0-PLACEHOLDER",
|
||||
"rxjs": "^5.5.0"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -21,5 +21,8 @@
|
||||
},
|
||||
"bin": {
|
||||
"ngsw-config": "./ngsw-config.js"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
@ -20,5 +20,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"ng-update": {
|
||||
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user