Revert "feat(upgrade): use `ComponentFactory.inputs/outputs/ngContentSelectors`"
This reverts commit a3e32fb7e1
.
This commit is contained in:
parent
a3e32fb7e1
commit
c439742a54
|
@ -156,6 +156,7 @@ export class CompileMetadataResolver {
|
||||||
const templateName = inputs[propName];
|
const templateName = inputs[propName];
|
||||||
factory.inputs.push({propName, templateName});
|
factory.inputs.push({propName, templateName});
|
||||||
}
|
}
|
||||||
|
const outputsArr: {propName: string, templateName: string}[] = [];
|
||||||
for (let propName in outputs) {
|
for (let propName in outputs) {
|
||||||
const templateName = outputs[propName];
|
const templateName = outputs[propName];
|
||||||
factory.outputs.push({propName, templateName});
|
factory.outputs.push({propName, templateName});
|
||||||
|
|
|
@ -279,6 +279,7 @@ describe('compiler (unbundled Angular)', () => {
|
||||||
const host = new MockCompilerHost(['/app/app.ts'], FILES, angularFiles);
|
const host = new MockCompilerHost(['/app/app.ts'], FILES, angularFiles);
|
||||||
const aotHost = new MockAotCompilerHost(host);
|
const aotHost = new MockAotCompilerHost(host);
|
||||||
let generatedFiles: GeneratedFile[];
|
let generatedFiles: GeneratedFile[];
|
||||||
|
const warnSpy = spyOn(console, 'warn');
|
||||||
compile(host, aotHost, expectNoDiagnostics).then((f) => generatedFiles = f);
|
compile(host, aotHost, expectNoDiagnostics).then((f) => generatedFiles = f);
|
||||||
|
|
||||||
tick();
|
tick();
|
||||||
|
|
|
@ -145,7 +145,12 @@ ng1AppModule.factory('heroesService', downgradeInjectable(HeroesService));
|
||||||
|
|
||||||
// #docregion ng2-heroes-wrapper
|
// #docregion ng2-heroes-wrapper
|
||||||
// This is directive will act as the interface to the "downgraded" Angular component
|
// This is directive will act as the interface to the "downgraded" Angular component
|
||||||
ng1AppModule.directive('ng2Heroes', downgradeComponent({component: Ng2HeroesComponent}));
|
ng1AppModule.directive(
|
||||||
|
'ng2Heroes',
|
||||||
|
downgradeComponent(
|
||||||
|
// The inputs and outputs here must match the relevant names of the properties on the
|
||||||
|
// "downgraded" component
|
||||||
|
{component: Ng2HeroesComponent, inputs: ['heroes'], outputs: ['addHero', 'removeHero']}));
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
||||||
// #docregion example-app
|
// #docregion example-app
|
||||||
|
|
|
@ -6,6 +6,15 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {Type} from '@angular/core';
|
||||||
|
|
||||||
|
export interface ComponentInfo {
|
||||||
|
component: Type<any>;
|
||||||
|
inputs?: string[];
|
||||||
|
outputs?: string[];
|
||||||
|
selectors?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `PropertyBinding` represents a mapping between a property name
|
* A `PropertyBinding` represents a mapping between a property name
|
||||||
* and an attribute name. It is parsed from a string of the form
|
* and an attribute name. It is parsed from a string of the form
|
||||||
|
@ -13,6 +22,8 @@
|
||||||
* and attribute have the same identifier.
|
* and attribute have the same identifier.
|
||||||
*/
|
*/
|
||||||
export class PropertyBinding {
|
export class PropertyBinding {
|
||||||
|
prop: string;
|
||||||
|
attr: string;
|
||||||
bracketAttr: string;
|
bracketAttr: string;
|
||||||
bracketParenAttr: string;
|
bracketParenAttr: string;
|
||||||
parenAttr: string;
|
parenAttr: string;
|
||||||
|
@ -20,9 +31,12 @@ export class PropertyBinding {
|
||||||
bindAttr: string;
|
bindAttr: string;
|
||||||
bindonAttr: string;
|
bindonAttr: string;
|
||||||
|
|
||||||
constructor(public prop: string, public attr: string) { this.parseBinding(); }
|
constructor(public binding: string) { this.parseBinding(); }
|
||||||
|
|
||||||
private parseBinding() {
|
private parseBinding() {
|
||||||
|
const parts = this.binding.split(':');
|
||||||
|
this.prop = parts[0].trim();
|
||||||
|
this.attr = (parts[1] || this.prop).trim();
|
||||||
this.bracketAttr = `[${this.attr}]`;
|
this.bracketAttr = `[${this.attr}]`;
|
||||||
this.parenAttr = `(${this.attr})`;
|
this.parenAttr = `(${this.attr})`;
|
||||||
this.bracketParenAttr = `[(${this.attr})]`;
|
this.bracketParenAttr = `[(${this.attr})]`;
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* @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 {Type} from '@angular/core';
|
||||||
|
import * as angular from './angular1';
|
||||||
|
|
||||||
|
|
||||||
|
export class ContentProjectionHelper {
|
||||||
|
groupProjectableNodes($injector: angular.IInjectorService, component: Type<any>, nodes: Node[]):
|
||||||
|
Node[][] {
|
||||||
|
// By default, do not support multi-slot projection,
|
||||||
|
// as `upgrade/static` does not support it yet.
|
||||||
|
return [nodes];
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import {ComponentFactory, ComponentFactoryResolver, Injector, Type} from '@angul
|
||||||
import * as angular from './angular1';
|
import * as angular from './angular1';
|
||||||
import {$COMPILE, $INJECTOR, $PARSE, INJECTOR_KEY, REQUIRE_INJECTOR, REQUIRE_NG_MODEL} from './constants';
|
import {$COMPILE, $INJECTOR, $PARSE, INJECTOR_KEY, REQUIRE_INJECTOR, REQUIRE_NG_MODEL} from './constants';
|
||||||
import {DowngradeComponentAdapter} from './downgrade_component_adapter';
|
import {DowngradeComponentAdapter} from './downgrade_component_adapter';
|
||||||
|
import {NgContentSelectorHelper} from './ng_content_selector_helper';
|
||||||
import {controllerKey, getComponentName} from './util';
|
import {controllerKey, getComponentName} from './util';
|
||||||
|
|
||||||
let downgradeCount = 0;
|
let downgradeCount = 0;
|
||||||
|
@ -37,6 +38,15 @@ let downgradeCount = 0;
|
||||||
*
|
*
|
||||||
* {@example upgrade/static/ts/module.ts region="ng2-heroes-wrapper"}
|
* {@example upgrade/static/ts/module.ts region="ng2-heroes-wrapper"}
|
||||||
*
|
*
|
||||||
|
* In this example you can see that we must provide information about the component being
|
||||||
|
* "downgraded". This is because once the AoT compiler has run, all metadata about the
|
||||||
|
* component has been removed from the code, and so cannot be inferred.
|
||||||
|
*
|
||||||
|
* We must do the following:
|
||||||
|
* * specify the Angular component class that is to be downgraded
|
||||||
|
* * specify all inputs and outputs that the AngularJS component expects
|
||||||
|
* * specify the selectors used in any `ng-content` elements in the component's template
|
||||||
|
*
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
* A helper function that returns a factory function to be used for registering an
|
* A helper function that returns a factory function to be used for registering an
|
||||||
|
@ -45,17 +55,28 @@ let downgradeCount = 0;
|
||||||
* The parameter contains information about the Component that is being downgraded:
|
* The parameter contains information about the Component that is being downgraded:
|
||||||
*
|
*
|
||||||
* * `component: Type<any>`: The type of the Component that will be downgraded
|
* * `component: Type<any>`: The type of the Component that will be downgraded
|
||||||
|
* * `inputs: string[]`: A collection of strings that specify what inputs the component accepts
|
||||||
|
* * `outputs: string[]`: A collection of strings that specify what outputs the component emits
|
||||||
|
* * `selectors: string[]`: A collection of strings that specify what selectors are expected on
|
||||||
|
* `ng-content` elements in the template to enable content projection (a.k.a. transclusion in
|
||||||
|
* AngularJS)
|
||||||
|
*
|
||||||
|
* The `inputs` and `outputs` are strings that map the names of properties to camelCased
|
||||||
|
* attribute names. They are of the form `"prop: attr"`; or simply `"propAndAttr" where the
|
||||||
|
* property and attribute have the same identifier.
|
||||||
|
*
|
||||||
|
* The `selectors` are the values of the `select` attribute of each of the `ng-content` elements
|
||||||
|
* that appear in the downgraded component's template.
|
||||||
|
* These selectors must be provided in the order that they appear in the template as they are
|
||||||
|
* mapped by index to the projected nodes.
|
||||||
*
|
*
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
export function downgradeComponent(info: {
|
export function downgradeComponent(info: /* ComponentInfo */ {
|
||||||
component: Type<any>;
|
component: Type<any>;
|
||||||
/** @deprecated since v4. This parameter is no longer used */
|
|
||||||
inputs?: string[];
|
inputs?: string[];
|
||||||
/** @deprecated since v4. This parameter is no longer used */
|
|
||||||
outputs?: string[];
|
outputs?: string[];
|
||||||
/** @deprecated since v4. This parameter is no longer used */
|
selectors?: string[]
|
||||||
selectors?: string[];
|
|
||||||
}): any /* angular.IInjectable */ {
|
}): any /* angular.IInjectable */ {
|
||||||
const idPrefix = `NG2_UPGRADE_${downgradeCount++}_`;
|
const idPrefix = `NG2_UPGRADE_${downgradeCount++}_`;
|
||||||
let idCount = 0;
|
let idCount = 0;
|
||||||
|
@ -93,7 +114,7 @@ export function downgradeComponent(info: {
|
||||||
const id = idPrefix + (idCount++);
|
const id = idPrefix + (idCount++);
|
||||||
const injectorPromise = new ParentInjectorPromise(element);
|
const injectorPromise = new ParentInjectorPromise(element);
|
||||||
const facade = new DowngradeComponentAdapter(
|
const facade = new DowngradeComponentAdapter(
|
||||||
id, element, attrs, scope, ngModel, injector, $injector, $compile, $parse,
|
id, info, element, attrs, scope, ngModel, injector, $injector, $compile, $parse,
|
||||||
componentFactory);
|
componentFactory);
|
||||||
|
|
||||||
const projectableNodes = facade.compileContents();
|
const projectableNodes = facade.compileContents();
|
||||||
|
|
|
@ -9,8 +9,9 @@
|
||||||
import {ChangeDetectorRef, ComponentFactory, ComponentRef, EventEmitter, Injector, OnChanges, ReflectiveInjector, SimpleChange, SimpleChanges, Type} from '@angular/core';
|
import {ChangeDetectorRef, ComponentFactory, ComponentRef, EventEmitter, Injector, OnChanges, ReflectiveInjector, SimpleChange, SimpleChanges, Type} from '@angular/core';
|
||||||
|
|
||||||
import * as angular from './angular1';
|
import * as angular from './angular1';
|
||||||
import {PropertyBinding} from './component_info';
|
import {ComponentInfo, PropertyBinding} from './component_info';
|
||||||
import {$SCOPE} from './constants';
|
import {$SCOPE} from './constants';
|
||||||
|
import {NgContentSelectorHelper} from './ng_content_selector_helper';
|
||||||
import {getAttributesAsArray, getComponentName, hookupNgModel} from './util';
|
import {getAttributesAsArray, getComponentName, hookupNgModel} from './util';
|
||||||
|
|
||||||
const INITIAL_VALUE = {
|
const INITIAL_VALUE = {
|
||||||
|
@ -26,7 +27,7 @@ export class DowngradeComponentAdapter {
|
||||||
private changeDetector: ChangeDetectorRef = null;
|
private changeDetector: ChangeDetectorRef = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private id: string, private element: angular.IAugmentedJQuery,
|
private id: string, private info: ComponentInfo, private element: angular.IAugmentedJQuery,
|
||||||
private attrs: angular.IAttributes, private scope: angular.IScope,
|
private attrs: angular.IAttributes, private scope: angular.IScope,
|
||||||
private ngModel: angular.INgModelController, private parentInjector: Injector,
|
private ngModel: angular.INgModelController, private parentInjector: Injector,
|
||||||
private $injector: angular.IInjectorService, private $compile: angular.ICompileService,
|
private $injector: angular.IInjectorService, private $compile: angular.ICompileService,
|
||||||
|
@ -66,9 +67,9 @@ export class DowngradeComponentAdapter {
|
||||||
|
|
||||||
setupInputs(): void {
|
setupInputs(): void {
|
||||||
const attrs = this.attrs;
|
const attrs = this.attrs;
|
||||||
const inputs = this.componentFactory.inputs || [];
|
const inputs = this.info.inputs || [];
|
||||||
for (let i = 0; i < inputs.length; i++) {
|
for (let i = 0; i < inputs.length; i++) {
|
||||||
const input = new PropertyBinding(inputs[i].propName, inputs[i].templateName);
|
const input = new PropertyBinding(inputs[i]);
|
||||||
let expr: any /** TODO #9100 */ = null;
|
let expr: any /** TODO #9100 */ = null;
|
||||||
|
|
||||||
if (attrs.hasOwnProperty(input.attr)) {
|
if (attrs.hasOwnProperty(input.attr)) {
|
||||||
|
@ -102,7 +103,7 @@ export class DowngradeComponentAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const prototype = this.componentFactory.componentType.prototype;
|
const prototype = this.info.component.prototype;
|
||||||
if (prototype && (<OnChanges>prototype).ngOnChanges) {
|
if (prototype && (<OnChanges>prototype).ngOnChanges) {
|
||||||
// Detect: OnChanges interface
|
// Detect: OnChanges interface
|
||||||
this.inputChanges = {};
|
this.inputChanges = {};
|
||||||
|
@ -117,9 +118,9 @@ export class DowngradeComponentAdapter {
|
||||||
|
|
||||||
setupOutputs() {
|
setupOutputs() {
|
||||||
const attrs = this.attrs;
|
const attrs = this.attrs;
|
||||||
const outputs = this.componentFactory.outputs || [];
|
const outputs = this.info.outputs || [];
|
||||||
for (let j = 0; j < outputs.length; j++) {
|
for (let j = 0; j < outputs.length; j++) {
|
||||||
const output = new PropertyBinding(outputs[j].propName, outputs[j].templateName);
|
const output = new PropertyBinding(outputs[j]);
|
||||||
let expr: any /** TODO #9100 */ = null;
|
let expr: any /** TODO #9100 */ = null;
|
||||||
let assignExpr = false;
|
let assignExpr = false;
|
||||||
|
|
||||||
|
@ -157,7 +158,7 @@ export class DowngradeComponentAdapter {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Missing emitter '${output.prop}' on component '${getComponentName(this.componentFactory.componentType)}'!`);
|
`Missing emitter '${output.prop}' on component '${getComponentName(this.info.component)}'!`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,31 +183,49 @@ export class DowngradeComponentAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
groupProjectableNodes() {
|
groupProjectableNodes() {
|
||||||
let ngContentSelectors = this.componentFactory.ngContentSelectors;
|
const ngContentSelectorHelper =
|
||||||
return groupNodesBySelector(ngContentSelectors, this.element.contents());
|
this.parentInjector.get(NgContentSelectorHelper) as NgContentSelectorHelper;
|
||||||
|
const ngContentSelectors = ngContentSelectorHelper.getNgContentSelectors(this.info);
|
||||||
|
|
||||||
|
if (!ngContentSelectors) {
|
||||||
|
throw new Error('Expecting ngContentSelectors for: ' + getComponentName(this.info.component));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._groupNodesBySelector(ngContentSelectors, this.element.contents());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group a set of DOM nodes into `ngContent` groups, based on the given content selectors.
|
||||||
|
*/
|
||||||
|
private _groupNodesBySelector(ngContentSelectors: string[], nodes: Node[]): Node[][] {
|
||||||
|
const projectableNodes: Node[][] = [];
|
||||||
|
let wildcardNgContentIndex: number;
|
||||||
|
|
||||||
|
for (let i = 0, ii = ngContentSelectors.length; i < ii; ++i) {
|
||||||
|
projectableNodes[i] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0, jj = nodes.length; j < jj; ++j) {
|
||||||
|
const node = nodes[j];
|
||||||
|
const ngContentIndex = findMatchingNgContentIndex(node, ngContentSelectors);
|
||||||
|
if (ngContentIndex != null) {
|
||||||
|
projectableNodes[ngContentIndex].push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return projectableNodes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
let _matches: (this: any, selector: string) => boolean;
|
||||||
* Group a set of DOM nodes into `ngContent` groups, based on the given content selectors.
|
|
||||||
*/
|
|
||||||
export function groupNodesBySelector(ngContentSelectors: string[], nodes: Node[]): Node[][] {
|
|
||||||
const projectableNodes: Node[][] = [];
|
|
||||||
let wildcardNgContentIndex: number;
|
|
||||||
|
|
||||||
for (let i = 0, ii = ngContentSelectors.length; i < ii; ++i) {
|
function matchesSelector(el: any, selector: string): boolean {
|
||||||
projectableNodes[i] = [];
|
if (!_matches) {
|
||||||
|
const elProto = <any>Element.prototype;
|
||||||
|
_matches = elProto.matchesSelector || elProto.mozMatchesSelector || elProto.msMatchesSelector ||
|
||||||
|
elProto.oMatchesSelector || elProto.webkitMatchesSelector;
|
||||||
}
|
}
|
||||||
|
return _matches.call(el, selector);
|
||||||
for (let j = 0, jj = nodes.length; j < jj; ++j) {
|
|
||||||
const node = nodes[j];
|
|
||||||
const ngContentIndex = findMatchingNgContentIndex(node, ngContentSelectors);
|
|
||||||
if (ngContentIndex != null) {
|
|
||||||
projectableNodes[ngContentIndex].push(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return projectableNodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function findMatchingNgContentIndex(element: any, ngContentSelectors: string[]): number {
|
function findMatchingNgContentIndex(element: any, ngContentSelectors: string[]): number {
|
||||||
|
@ -229,14 +248,3 @@ function findMatchingNgContentIndex(element: any, ngContentSelectors: string[]):
|
||||||
}
|
}
|
||||||
return ngContentIndices.length ? ngContentIndices[0] : null;
|
return ngContentIndices.length ? ngContentIndices[0] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _matches: (this: any, selector: string) => boolean;
|
|
||||||
|
|
||||||
function matchesSelector(el: any, selector: string): boolean {
|
|
||||||
if (!_matches) {
|
|
||||||
const elProto = <any>Element.prototype;
|
|
||||||
_matches = elProto.matches || elProto.matchesSelector || elProto.mozMatchesSelector ||
|
|
||||||
elProto.msMatchesSelector || elProto.oMatchesSelector || elProto.webkitMatchesSelector;
|
|
||||||
}
|
|
||||||
return el.nodeType === Node.ELEMENT_NODE ? _matches.call(el, selector) : false;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* @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 {ComponentInfo} from './component_info';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class gives an extension point between the static and dynamic versions
|
||||||
|
* of ngUpgrade:
|
||||||
|
* * In the static version (this one) we must specify them manually as part of
|
||||||
|
* the call to `downgradeComponent(...)`.
|
||||||
|
* * In the dynamic version (`DynamicNgContentSelectorHelper`) we are able to
|
||||||
|
* ask the compiler for the selectors of a component.
|
||||||
|
*/
|
||||||
|
export class NgContentSelectorHelper {
|
||||||
|
getNgContentSelectors(info: ComponentInfo): string[] {
|
||||||
|
// if no selectors are passed then default to a single "wildcard" selector
|
||||||
|
return info.selectors || ['*'];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/**
|
||||||
|
* @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 {CssSelector, SelectorMatcher, createElementCssSelector} from '@angular/compiler';
|
||||||
|
import {Compiler, Type} from '@angular/core';
|
||||||
|
|
||||||
|
import * as angular from '../common/angular1';
|
||||||
|
import {COMPILER_KEY} from '../common/constants';
|
||||||
|
import {ContentProjectionHelper} from '../common/content_projection_helper';
|
||||||
|
import {getAttributesAsArray, getComponentName} from '../common/util';
|
||||||
|
|
||||||
|
|
||||||
|
export class DynamicContentProjectionHelper extends ContentProjectionHelper {
|
||||||
|
groupProjectableNodes($injector: angular.IInjectorService, component: Type<any>, nodes: Node[]):
|
||||||
|
Node[][] {
|
||||||
|
const ng2Compiler = $injector.get(COMPILER_KEY) as Compiler;
|
||||||
|
const ngContentSelectors = ng2Compiler.getNgContentSelectors(component);
|
||||||
|
|
||||||
|
if (!ngContentSelectors) {
|
||||||
|
throw new Error('Expecting ngContentSelectors for: ' + getComponentName(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.groupNodesBySelector(ngContentSelectors, nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group a set of DOM nodes into `ngContent` groups, based on the given content selectors.
|
||||||
|
*/
|
||||||
|
groupNodesBySelector(ngContentSelectors: string[], nodes: Node[]): Node[][] {
|
||||||
|
const projectableNodes: Node[][] = [];
|
||||||
|
let matcher = new SelectorMatcher();
|
||||||
|
let wildcardNgContentIndex: number;
|
||||||
|
|
||||||
|
for (let i = 0, ii = ngContentSelectors.length; i < ii; ++i) {
|
||||||
|
projectableNodes[i] = [];
|
||||||
|
|
||||||
|
const selector = ngContentSelectors[i];
|
||||||
|
if (selector === '*') {
|
||||||
|
wildcardNgContentIndex = i;
|
||||||
|
} else {
|
||||||
|
matcher.addSelectables(CssSelector.parse(selector), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0, jj = nodes.length; j < jj; ++j) {
|
||||||
|
const ngContentIndices: number[] = [];
|
||||||
|
const node = nodes[j];
|
||||||
|
const selector =
|
||||||
|
createElementCssSelector(node.nodeName.toLowerCase(), getAttributesAsArray(node));
|
||||||
|
|
||||||
|
matcher.match(selector, (_, index) => ngContentIndices.push(index));
|
||||||
|
ngContentIndices.sort();
|
||||||
|
|
||||||
|
if (wildcardNgContentIndex !== undefined) {
|
||||||
|
ngContentIndices.push(wildcardNgContentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngContentIndices.length) {
|
||||||
|
projectableNodes[ngContentIndices[0]].push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return projectableNodes;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* @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 {Compiler, Injectable} from '@angular/core';
|
||||||
|
|
||||||
|
import {ComponentInfo} from '../common/component_info';
|
||||||
|
import {NgContentSelectorHelper} from '../common/ng_content_selector_helper';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `NgContentSelectorHelper` for more information about this class.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class DynamicNgContentSelectorHelper extends NgContentSelectorHelper {
|
||||||
|
constructor(private compiler: Compiler) { super(); }
|
||||||
|
getNgContentSelectors(info: ComponentInfo): string[] {
|
||||||
|
return this.compiler.getNgContentSelectors(info.component);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,15 +6,19 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {DirectiveResolver} from '@angular/compiler';
|
||||||
import {Compiler, CompilerOptions, Directive, Injector, NgModule, NgModuleRef, NgZone, Provider, Testability, Type} from '@angular/core';
|
import {Compiler, CompilerOptions, Directive, Injector, NgModule, NgModuleRef, NgZone, Provider, Testability, Type} from '@angular/core';
|
||||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
import * as angular from '../common/angular1';
|
import * as angular from '../common/angular1';
|
||||||
|
import {ComponentInfo} from '../common/component_info';
|
||||||
import {$$TESTABILITY, $COMPILE, $INJECTOR, $ROOT_SCOPE, COMPILER_KEY, INJECTOR_KEY, NG_ZONE_KEY} from '../common/constants';
|
import {$$TESTABILITY, $COMPILE, $INJECTOR, $ROOT_SCOPE, COMPILER_KEY, INJECTOR_KEY, NG_ZONE_KEY} from '../common/constants';
|
||||||
import {downgradeComponent} from '../common/downgrade_component';
|
import {downgradeComponent} from '../common/downgrade_component';
|
||||||
import {downgradeInjectable} from '../common/downgrade_injectable';
|
import {downgradeInjectable} from '../common/downgrade_injectable';
|
||||||
|
import {NgContentSelectorHelper} from '../common/ng_content_selector_helper';
|
||||||
import {Deferred, controllerKey, onError} from '../common/util';
|
import {Deferred, controllerKey, onError} from '../common/util';
|
||||||
|
|
||||||
|
import {DynamicNgContentSelectorHelper} from './ng_content_selector_helper';
|
||||||
import {UpgradeNg1ComponentAdapterBuilder} from './upgrade_ng1_adapter';
|
import {UpgradeNg1ComponentAdapterBuilder} from './upgrade_ng1_adapter';
|
||||||
|
|
||||||
let upgradeCount: number = 0;
|
let upgradeCount: number = 0;
|
||||||
|
@ -100,6 +104,7 @@ let upgradeCount: number = 0;
|
||||||
*/
|
*/
|
||||||
export class UpgradeAdapter {
|
export class UpgradeAdapter {
|
||||||
private idPrefix: string = `NG2_UPGRADE_${upgradeCount++}_`;
|
private idPrefix: string = `NG2_UPGRADE_${upgradeCount++}_`;
|
||||||
|
private directiveResolver: DirectiveResolver = new DirectiveResolver();
|
||||||
private downgradedComponents: Type<any>[] = [];
|
private downgradedComponents: Type<any>[] = [];
|
||||||
/**
|
/**
|
||||||
* An internal map of ng1 components which need to up upgraded to ng2.
|
* An internal map of ng1 components which need to up upgraded to ng2.
|
||||||
|
@ -185,7 +190,10 @@ export class UpgradeAdapter {
|
||||||
downgradeNg2Component(component: Type<any>): Function {
|
downgradeNg2Component(component: Type<any>): Function {
|
||||||
this.downgradedComponents.push(component);
|
this.downgradedComponents.push(component);
|
||||||
|
|
||||||
return downgradeComponent({component});
|
const metadata: Directive = this.directiveResolver.resolve(component);
|
||||||
|
const info: ComponentInfo = {component, inputs: metadata.inputs, outputs: metadata.outputs};
|
||||||
|
|
||||||
|
return downgradeComponent(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -553,6 +561,7 @@ export class UpgradeAdapter {
|
||||||
providers: [
|
providers: [
|
||||||
{provide: $INJECTOR, useFactory: () => ng1Injector},
|
{provide: $INJECTOR, useFactory: () => ng1Injector},
|
||||||
{provide: $COMPILE, useFactory: () => ng1Injector.get($COMPILE)},
|
{provide: $COMPILE, useFactory: () => ng1Injector.get($COMPILE)},
|
||||||
|
{provide: NgContentSelectorHelper, useClass: DynamicNgContentSelectorHelper},
|
||||||
this.upgradedProviders
|
this.upgradedProviders
|
||||||
],
|
],
|
||||||
imports: [this.ng2AppModule],
|
imports: [this.ng2AppModule],
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {Injector, NgModule, NgZone, Testability} from '@angular/core';
|
||||||
|
|
||||||
import * as angular from '../common/angular1';
|
import * as angular from '../common/angular1';
|
||||||
import {$$TESTABILITY, $DELEGATE, $INJECTOR, $PROVIDE, $ROOT_SCOPE, INJECTOR_KEY, UPGRADE_MODULE_NAME} from '../common/constants';
|
import {$$TESTABILITY, $DELEGATE, $INJECTOR, $PROVIDE, $ROOT_SCOPE, INJECTOR_KEY, UPGRADE_MODULE_NAME} from '../common/constants';
|
||||||
|
import {NgContentSelectorHelper} from '../common/ng_content_selector_helper';
|
||||||
import {controllerKey} from '../common/util';
|
import {controllerKey} from '../common/util';
|
||||||
|
|
||||||
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
|
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
|
||||||
|
@ -129,7 +130,7 @@ import {angular1Providers, setTempInjectorRef} from './angular1_providers';
|
||||||
*
|
*
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
@NgModule({providers: [angular1Providers]})
|
@NgModule({providers: [angular1Providers, NgContentSelectorHelper]})
|
||||||
export class UpgradeModule {
|
export class UpgradeModule {
|
||||||
/**
|
/**
|
||||||
* The AngularJS `$injector` for the upgrade application.
|
* The AngularJS `$injector` for the upgrade application.
|
||||||
|
|
|
@ -11,7 +11,8 @@ import {PropertyBinding} from '@angular/upgrade/src/common/component_info';
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('PropertyBinding', () => {
|
describe('PropertyBinding', () => {
|
||||||
it('should process a simple binding', () => {
|
it('should process a simple binding', () => {
|
||||||
const binding = new PropertyBinding('someBinding', 'someBinding');
|
const binding = new PropertyBinding('someBinding');
|
||||||
|
expect(binding.binding).toEqual('someBinding');
|
||||||
expect(binding.prop).toEqual('someBinding');
|
expect(binding.prop).toEqual('someBinding');
|
||||||
expect(binding.attr).toEqual('someBinding');
|
expect(binding.attr).toEqual('someBinding');
|
||||||
expect(binding.bracketAttr).toEqual('[someBinding]');
|
expect(binding.bracketAttr).toEqual('[someBinding]');
|
||||||
|
@ -23,7 +24,21 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should process a two-part binding', () => {
|
it('should process a two-part binding', () => {
|
||||||
const binding = new PropertyBinding('someProp', 'someAttr');
|
const binding = new PropertyBinding('someProp:someAttr');
|
||||||
|
expect(binding.binding).toEqual('someProp:someAttr');
|
||||||
|
expect(binding.prop).toEqual('someProp');
|
||||||
|
expect(binding.attr).toEqual('someAttr');
|
||||||
|
expect(binding.bracketAttr).toEqual('[someAttr]');
|
||||||
|
expect(binding.bracketParenAttr).toEqual('[(someAttr)]');
|
||||||
|
expect(binding.parenAttr).toEqual('(someAttr)');
|
||||||
|
expect(binding.onAttr).toEqual('onSomeAttr');
|
||||||
|
expect(binding.bindAttr).toEqual('bindSomeAttr');
|
||||||
|
expect(binding.bindonAttr).toEqual('bindonSomeAttr');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cope with whitespace', () => {
|
||||||
|
const binding = new PropertyBinding(' someProp : someAttr ');
|
||||||
|
expect(binding.binding).toEqual(' someProp : someAttr ');
|
||||||
expect(binding.prop).toEqual('someProp');
|
expect(binding.prop).toEqual('someProp');
|
||||||
expect(binding.attr).toEqual('someAttr');
|
expect(binding.attr).toEqual('someAttr');
|
||||||
expect(binding.bracketAttr).toEqual('[someAttr]');
|
expect(binding.bracketAttr).toEqual('[someAttr]');
|
||||||
|
|
|
@ -6,13 +6,25 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||||
import {groupNodesBySelector} from '@angular/upgrade/src/common/downgrade_component_adapter';
|
import {DowngradeComponentAdapter} from '@angular/upgrade/src/common/downgrade_component_adapter';
|
||||||
|
import {NgContentSelectorHelper} from '@angular/upgrade/src/common/ng_content_selector_helper';
|
||||||
import {nodes} from './test_helpers';
|
import {nodes} from './test_helpers';
|
||||||
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('DowngradeComponentAdapter', () => {
|
describe('DowngradeComponentAdapter', () => {
|
||||||
describe('groupNodesBySelector', () => {
|
describe('groupNodesBySelector', () => {
|
||||||
|
function createAdapter(selectors: string[], contentNodes: Node[]): DowngradeComponentAdapter {
|
||||||
|
const selectorHelper = new NgContentSelectorHelper();
|
||||||
|
const fakeInjector = {get: function() { return selectorHelper; }};
|
||||||
|
const fakeScope = { $new: function() {} } as any;
|
||||||
|
const element = angular.element('<div></div>');
|
||||||
|
element.append(contentNodes);
|
||||||
|
return new DowngradeComponentAdapter(
|
||||||
|
'id', {component: null, selectors}, element, null, fakeScope, null, fakeInjector, null,
|
||||||
|
null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
it('should return an array of node collections for each selector', () => {
|
it('should return an array of node collections for each selector', () => {
|
||||||
const contentNodes = nodes(
|
const contentNodes = nodes(
|
||||||
'<div class="x"><span>div-1 content</span></div>' +
|
'<div class="x"><span>div-1 content</span></div>' +
|
||||||
|
@ -22,7 +34,8 @@ export function main() {
|
||||||
'<div class="x"><span>div-2 content</span></div>');
|
'<div class="x"><span>div-2 content</span></div>');
|
||||||
|
|
||||||
const selectors = ['input[type=date]', 'span', '.x'];
|
const selectors = ['input[type=date]', 'span', '.x'];
|
||||||
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
|
const adapter = createAdapter(selectors, contentNodes);
|
||||||
|
const projectableNodes = adapter.groupProjectableNodes();
|
||||||
|
|
||||||
expect(projectableNodes[0]).toEqual(nodes('<input type="date" name="myDate">'));
|
expect(projectableNodes[0]).toEqual(nodes('<input type="date" name="myDate">'));
|
||||||
expect(projectableNodes[1]).toEqual(nodes('<span>span content</span>'));
|
expect(projectableNodes[1]).toEqual(nodes('<span>span content</span>'));
|
||||||
|
@ -41,7 +54,8 @@ export function main() {
|
||||||
'<div class="x"><span>div-2 content</span></div>');
|
'<div class="x"><span>div-2 content</span></div>');
|
||||||
|
|
||||||
const selectors = ['.x', '*', 'input[type=date]'];
|
const selectors = ['.x', '*', 'input[type=date]'];
|
||||||
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
|
const adapter = createAdapter(selectors, contentNodes);
|
||||||
|
const projectableNodes = adapter.groupProjectableNodes();
|
||||||
|
|
||||||
expect(projectableNodes[0])
|
expect(projectableNodes[0])
|
||||||
.toEqual(nodes(
|
.toEqual(nodes(
|
||||||
|
@ -56,7 +70,8 @@ export function main() {
|
||||||
|
|
||||||
it('should return an array of empty arrays if there are no nodes passed in', () => {
|
it('should return an array of empty arrays if there are no nodes passed in', () => {
|
||||||
const selectors = ['.x', '*', 'input[type=date]'];
|
const selectors = ['.x', '*', 'input[type=date]'];
|
||||||
const projectableNodes = groupNodesBySelector(selectors, []);
|
const adapter = createAdapter(selectors, []);
|
||||||
|
const projectableNodes = adapter.groupProjectableNodes();
|
||||||
expect(projectableNodes).toEqual([[], [], []]);
|
expect(projectableNodes).toEqual([[], [], []]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -68,10 +83,12 @@ export function main() {
|
||||||
'<span>span content</span>' +
|
'<span>span content</span>' +
|
||||||
'<div class="x"><span>div-2 content</span></div>');
|
'<div class="x"><span>div-2 content</span></div>');
|
||||||
|
|
||||||
const projectableNodes = groupNodesBySelector([], contentNodes);
|
const adapter1 = createAdapter([], contentNodes);
|
||||||
|
const projectableNodes = adapter1.groupProjectableNodes();
|
||||||
expect(projectableNodes).toEqual([]);
|
expect(projectableNodes).toEqual([]);
|
||||||
|
|
||||||
const noMatchSelectorNodes = groupNodesBySelector(['.not-there'], contentNodes);
|
const adapter2 = createAdapter(['.not-there'], contentNodes);
|
||||||
|
const noMatchSelectorNodes = adapter2.groupProjectableNodes();
|
||||||
expect(noMatchSelectorNodes).toEqual([[]]);
|
expect(noMatchSelectorNodes).toEqual([[]]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/**
|
||||||
|
* @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 {DynamicContentProjectionHelper} from '@angular/upgrade/src/dynamic/content_projection_helper';
|
||||||
|
import {nodes} from './test_helpers';
|
||||||
|
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
describe('groupNodesBySelector', () => {
|
||||||
|
let groupNodesBySelector: (ngContentSelectors: string[], nodes: Node[]) => Node[][];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const projectionHelper = new DynamicContentProjectionHelper();
|
||||||
|
groupNodesBySelector = projectionHelper.groupNodesBySelector.bind(projectionHelper);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should return an array of node collections for each selector', () => {
|
||||||
|
const contentNodes = nodes(
|
||||||
|
'<div class="x"><span>div-1 content</span></div>' +
|
||||||
|
'<input type="number" name="myNum">' +
|
||||||
|
'<input type="date" name="myDate">' +
|
||||||
|
'<span>span content</span>' +
|
||||||
|
'<div class="x"><span>div-2 content</span></div>');
|
||||||
|
|
||||||
|
const selectors = ['input[type=date]', 'span', '.x'];
|
||||||
|
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
|
||||||
|
|
||||||
|
expect(projectableNodes[0]).toEqual(nodes('<input type="date" name="myDate">'));
|
||||||
|
expect(projectableNodes[1]).toEqual(nodes('<span>span content</span>'));
|
||||||
|
expect(projectableNodes[2])
|
||||||
|
.toEqual(nodes(
|
||||||
|
'<div class="x"><span>div-1 content</span></div>' +
|
||||||
|
'<div class="x"><span>div-2 content</span></div>'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should collect up unmatched nodes for the wildcard selector', () => {
|
||||||
|
const contentNodes = nodes(
|
||||||
|
'<div class="x"><span>div-1 content</span></div>' +
|
||||||
|
'<input type="number" name="myNum">' +
|
||||||
|
'<input type="date" name="myDate">' +
|
||||||
|
'<span>span content</span>' +
|
||||||
|
'<div class="x"><span>div-2 content</span></div>');
|
||||||
|
|
||||||
|
const selectors = ['.x', '*', 'input[type=date]'];
|
||||||
|
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
|
||||||
|
|
||||||
|
expect(projectableNodes[0])
|
||||||
|
.toEqual(nodes(
|
||||||
|
'<div class="x"><span>div-1 content</span></div>' +
|
||||||
|
'<div class="x"><span>div-2 content</span></div>'));
|
||||||
|
expect(projectableNodes[1])
|
||||||
|
.toEqual(nodes(
|
||||||
|
'<input type="number" name="myNum">' +
|
||||||
|
'<span>span content</span>'));
|
||||||
|
expect(projectableNodes[2]).toEqual(nodes('<input type="date" name="myDate">'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an array of empty arrays if there are no nodes passed in', () => {
|
||||||
|
const selectors = ['.x', '*', 'input[type=date]'];
|
||||||
|
const projectableNodes = groupNodesBySelector(selectors, []);
|
||||||
|
expect(projectableNodes).toEqual([[], [], []]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an empty array for each selector that does not match', () => {
|
||||||
|
const contentNodes = nodes(
|
||||||
|
'<div class="x"><span>div-1 content</span></div>' +
|
||||||
|
'<input type="number" name="myNum">' +
|
||||||
|
'<input type="date" name="myDate">' +
|
||||||
|
'<span>span content</span>' +
|
||||||
|
'<div class="x"><span>div-2 content</span></div>');
|
||||||
|
|
||||||
|
const noSelectorNodes = groupNodesBySelector([], contentNodes);
|
||||||
|
expect(noSelectorNodes).toEqual([]);
|
||||||
|
|
||||||
|
const noMatchSelectorNodes = groupNodesBySelector(['.not-there'], contentNodes);
|
||||||
|
expect(noMatchSelectorNodes).toEqual([[]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -73,7 +73,7 @@ export function main() {
|
||||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||||
expect(document.body.textContent).toEqual('1A;2A;ng1a;2B;ng1b;2C;1C;');
|
expect(document.body.textContent).toEqual('1A;2A;ng1a;2B;ng1b;2C;1C;');
|
||||||
// https://github.com/angular/angular.js/issues/12983
|
// https://github.com/angular/angular.js/issues/12983
|
||||||
expect(log).toEqual(['1A', '1C', '2A', '2B', '2C', 'ng1a', 'ng1b']);
|
expect(log).toEqual(['1A', '1B', '1C', '2A', '2B', '2C', 'ng1a', 'ng1b']);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -72,14 +72,16 @@ export function main() {
|
||||||
ngDoBootstrap() {}
|
ngDoBootstrap() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ng1Module = angular.module('ng1', [])
|
const ng1Module =
|
||||||
.directive('ng2', downgradeComponent({component: Ng2Component}))
|
angular.module('ng1', [])
|
||||||
.run(($rootScope: angular.IRootScopeService) => {
|
.directive(
|
||||||
$rootScope['items'] = [
|
'ng2', downgradeComponent({component: Ng2Component, inputs: ['itemId']}))
|
||||||
{id: 'a', subitems: [1, 2, 3]}, {id: 'b', subitems: [4, 5, 6]},
|
.run(($rootScope: angular.IRootScopeService) => {
|
||||||
{id: 'c', subitems: [7, 8, 9]}
|
$rootScope['items'] = [
|
||||||
];
|
{id: 'a', subitems: [1, 2, 3]}, {id: 'b', subitems: [4, 5, 6]},
|
||||||
});
|
{id: 'c', subitems: [7, 8, 9]}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
const element = html(`
|
const element = html(`
|
||||||
<ng2 ng-repeat="item in items" [item-id]="item.id">
|
<ng2 ng-repeat="item in items" [item-id]="item.id">
|
||||||
|
@ -160,7 +162,7 @@ export function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ng1Module = angular.module('ng1', []).directive(
|
const ng1Module = angular.module('ng1', []).directive(
|
||||||
'ng2', downgradeComponent({component: Ng2Component}));
|
'ng2', downgradeComponent({component: Ng2Component, selectors: ['.ng1a', '.ng1b']}));
|
||||||
|
|
||||||
// The ng-if on one of the projected children is here to make sure
|
// The ng-if on one of the projected children is here to make sure
|
||||||
// the correct slot is targeted even with structural directives in play.
|
// the correct slot is targeted even with structural directives in play.
|
||||||
|
|
|
@ -108,9 +108,15 @@ export function main() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ng1Module.directive('ng2', downgradeComponent({
|
ng1Module.directive(
|
||||||
component: Ng2Component,
|
'ng2', downgradeComponent({
|
||||||
}));
|
component: Ng2Component,
|
||||||
|
inputs: ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'],
|
||||||
|
outputs: [
|
||||||
|
'eventA', 'eventB', 'twoWayAEmitter: twoWayAChange',
|
||||||
|
'twoWayBEmitter: twoWayBChange'
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [Ng2Component],
|
declarations: [Ng2Component],
|
||||||
|
|
|
@ -71,7 +71,9 @@ export function main() {
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
// This is wrapping (downgrading) an Angular component to be used in AngularJS
|
// This is wrapping (downgrading) an Angular component to be used in AngularJS
|
||||||
.directive('ng2', downgradeComponent({component: Ng2Component}));
|
.directive(
|
||||||
|
'ng2',
|
||||||
|
downgradeComponent({component: Ng2Component, inputs: ['nameProp: name']}));
|
||||||
|
|
||||||
// This is the (AngularJS) application bootstrap element
|
// This is the (AngularJS) application bootstrap element
|
||||||
// Notice that it is actually a downgraded Angular component
|
// Notice that it is actually a downgraded Angular component
|
||||||
|
|
|
@ -2627,10 +2627,12 @@ export function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define `ng1Module`
|
// Define `ng1Module`
|
||||||
const ng1Module = angular.module('ng1Module', [])
|
const ng1Module =
|
||||||
.directive('ng1A', () => ng1DirectiveA)
|
angular.module('ng1Module', [])
|
||||||
.directive('ng1B', () => ng1DirectiveB)
|
.directive('ng1A', () => ng1DirectiveA)
|
||||||
.directive('ng2', downgradeComponent({component: Ng2Component}));
|
.directive('ng1B', () => ng1DirectiveB)
|
||||||
|
.directive(
|
||||||
|
'ng2', downgradeComponent({component: Ng2Component, inputs: ['show']}));
|
||||||
|
|
||||||
// Define `Ng2Module`
|
// Define `Ng2Module`
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -2727,10 +2729,12 @@ export function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define `ng1Module`
|
// Define `ng1Module`
|
||||||
const ng1Module = angular.module('ng1Module', [])
|
const ng1Module =
|
||||||
.directive('ng1A', () => ng1DirectiveA)
|
angular.module('ng1Module', [])
|
||||||
.directive('ng1B', () => ng1DirectiveB)
|
.directive('ng1A', () => ng1DirectiveA)
|
||||||
.directive('ng2', downgradeComponent({component: Ng2Component}));
|
.directive('ng1B', () => ng1DirectiveB)
|
||||||
|
.directive(
|
||||||
|
'ng2', downgradeComponent({component: Ng2Component, inputs: ['show']}));
|
||||||
|
|
||||||
// Define `Ng2Module`
|
// Define `Ng2Module`
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -3082,7 +3086,11 @@ export function main() {
|
||||||
const ng1Module = angular.module('ng1', [])
|
const ng1Module = angular.module('ng1', [])
|
||||||
.component('ng1X', ng1Component)
|
.component('ng1X', ng1Component)
|
||||||
.directive('ng2A', downgradeComponent({component: Ng2ComponentA}))
|
.directive('ng2A', downgradeComponent({component: Ng2ComponentA}))
|
||||||
.directive('ng2B', downgradeComponent({component: Ng2ComponentB}));
|
.directive('ng2B', downgradeComponent({
|
||||||
|
component: Ng2ComponentB,
|
||||||
|
inputs: ['ng2BInputA: ng2BInput1', 'ng2BInputC'],
|
||||||
|
outputs: ['ng2BOutputC']
|
||||||
|
}));
|
||||||
|
|
||||||
// Define `Ng2Module`
|
// Define `Ng2Module`
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -193,7 +193,7 @@ export declare class Compiler {
|
||||||
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T>;
|
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T>;
|
||||||
compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>>;
|
compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>>;
|
||||||
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T>;
|
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T>;
|
||||||
/** @deprecated */ getNgContentSelectors(component: Type<any>): string[];
|
getNgContentSelectors(component: Type<any>): string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @experimental */
|
/** @experimental */
|
||||||
|
@ -226,15 +226,6 @@ export interface ComponentDecorator {
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare abstract class ComponentFactory<C> {
|
export declare abstract class ComponentFactory<C> {
|
||||||
readonly abstract componentType: Type<any>;
|
readonly abstract componentType: Type<any>;
|
||||||
readonly abstract inputs: {
|
|
||||||
propName: string;
|
|
||||||
templateName: string;
|
|
||||||
}[];
|
|
||||||
readonly abstract ngContentSelectors: string[];
|
|
||||||
readonly abstract outputs: {
|
|
||||||
propName: string;
|
|
||||||
templateName: string;
|
|
||||||
}[];
|
|
||||||
readonly abstract selector: string;
|
readonly abstract selector: string;
|
||||||
abstract create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string | any, ngModule?: NgModuleRef<any>): ComponentRef<C>;
|
abstract create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string | any, ngModule?: NgModuleRef<any>): ComponentRef<C>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/** @experimental */
|
/** @experimental */
|
||||||
export declare function downgradeComponent(info: {
|
export declare function downgradeComponent(info: {
|
||||||
component: Type<any>;
|
component: Type<any>;
|
||||||
/** @deprecated */ inputs?: string[];
|
inputs?: string[];
|
||||||
/** @deprecated */ outputs?: string[];
|
outputs?: string[];
|
||||||
/** @deprecated */ selectors?: string[];
|
selectors?: string[];
|
||||||
}): any;
|
}): any;
|
||||||
|
|
||||||
/** @experimental */
|
/** @experimental */
|
||||||
|
|
Loading…
Reference in New Issue