feat(ngUpgrade): support for content project from ng1->ng2

This commit is contained in:
Misko Hevery
2015-10-09 14:53:04 -07:00
parent 867c08ac84
commit cd90e6ed8f
9 changed files with 93 additions and 28 deletions

View File

@ -25,7 +25,7 @@ declare namespace angular {
require?: string;
restrict?: string;
scope?: {[key: string]: string};
link?: Function;
link?: {pre?: Function, post?: Function};
}
interface IAttributes {
$observe(attr: string, fn: (v: string) => void);
@ -33,6 +33,10 @@ declare namespace angular {
interface ITranscludeFunction {}
interface IAugmentedJQuery {
bind(name: string, fn: () => void);
data(name: string, value?: any);
contents(): IAugmentedJQuery;
length: number;
[index: number]: Node;
}
interface IParseService {
(expression: string): ICompiledExpression;
@ -40,7 +44,7 @@ declare namespace angular {
interface ICompiledExpression {
assign(context: any, value: any): any;
}
function element(e: Element);
function element(e: Element): IAugmentedJQuery;
function bootstrap(e: Element, modules: IModule[], config: IAngularBootstrapConfig);
namespace auto {

View File

@ -5,10 +5,13 @@ import {
HostViewRef,
Injector,
ProtoViewRef,
SimpleChange
SimpleChange,
ViewRef
} from 'angular2/angular2';
import {NG1_SCOPE} from './constants';
import {ComponentInfo} from './metadata';
import {ViewRef_} from "../../angular2/src/core/linker/view_ref";
import Element = protractor.Element;
const INITIAL_VALUE = {
__UNINITIALIZED__: true
@ -21,13 +24,17 @@ export class Ng2ComponentFacade {
hostViewRef: HostViewRef = null;
changeDetector: ChangeDetectorRef = null;
componentScope: angular.IScope;
childNodes: Node[];
contentInserctionPoint: Node = null;
constructor(private id: string, private info: ComponentInfo,
private element: angular.IAugmentedJQuery, private attrs: angular.IAttributes,
private scope: angular.IScope, private parentInjector: Injector,
private parse: angular.IParseService, private viewManager: AppViewManager,
private protoView: ProtoViewRef) {
(<any>this.element[0]).id = id;
this.componentScope = scope.$new();
this.childNodes = <Node[]><any>element.contents();
}
bootstrapNg2() {
@ -35,9 +42,11 @@ export class Ng2ComponentFacade {
this.parentInjector.resolveAndCreateChild([bind(NG1_SCOPE).toValue(this.componentScope)]);
this.hostViewRef =
this.viewManager.createRootHostView(this.protoView, '#' + this.id, childInjector);
var renderer: any = (<any>this.hostViewRef).render;
var hostElement = this.viewManager.getHostElement(this.hostViewRef);
this.changeDetector = this.hostViewRef.changeDetectorRef;
this.component = this.viewManager.getComponent(hostElement);
this.contentInserctionPoint = renderer.rootContentInsertionPoints[0];
}
setupInputs() {
@ -94,6 +103,16 @@ export class Ng2ComponentFacade {
this.componentScope.$watch(() => this.changeDetector.detectChanges());
}
projectContent() {
var childNodes = this.childNodes;
if (this.contentInserctionPoint) {
var parent = this.contentInserctionPoint.parentNode;
for (var i = 0, ii = childNodes.length; i < ii; i++) {
parent.insertBefore(childNodes[i], this.contentInserctionPoint);
}
}
}
setupOutputs() {
var attrs = this.attrs;
var outputs = this.info.outputs;

View File

@ -169,16 +169,19 @@ function ng1ComponentDirective(info: ComponentInfo, idPrefix: string): Function
return {
restrict: 'E',
require: REQUIRE_INJECTOR,
link: (scope: angular.IScope, element: angular.IAugmentedJQuery, attrs: angular.IAttributes,
parentInjector: any, transclude: angular.ITranscludeFunction): void => {
var facade =
new Ng2ComponentFacade(element[0].id = idPrefix + (idCount++), info, element, attrs,
scope, <Injector>parentInjector, parse, viewManager, protoView);
facade.setupInputs();
facade.bootstrapNg2();
facade.setupOutputs();
facade.registerCleanup();
link: {
post: (scope: angular.IScope, element: angular.IAugmentedJQuery, attrs: angular.IAttributes,
parentInjector: any, transclude: angular.ITranscludeFunction): void => {
var domElement = <any>element[0];
var facade =
new Ng2ComponentFacade(idPrefix + (idCount++), info, element, attrs, scope,
<Injector>parentInjector, parse, viewManager, protoView);
facade.setupInputs();
facade.bootstrapNg2();
facade.projectContent();
facade.setupOutputs();
facade.registerCleanup();
}
}
};
}

View File

@ -18,17 +18,18 @@ export function main() {
describe('upgrade: ng1 to ng2', () => {
it('should have angular 1 loaded', () => expect(angular.version.major).toBe(1));
it('should instantiate ng2 in ng1 template', inject([AsyncTestCompleter], (async) => {
it('should instantiate ng2 in ng1 template and project content',
inject([AsyncTestCompleter], (async) => {
var Ng2 = Component({selector: 'ng2'})
.View({template: `{{ 'NG2' }}`})
.View({template: `{{ 'NG2' }}(<ng-content></ng-content>)`})
.Class({constructor: function() {}});
var element = html("<div>{{ 'ng1-' }}<ng2>~~</ng2>{{ '-ng1' }}</div>");
var element = html("<div>{{ 'ng1[' }}<ng2>~{{ 'ng-content' }}~</ng2>{{ ']' }}</div>");
var upgradeModule: UpgradeModule = createUpgradeModule();
upgradeModule.importNg2Component(Ng2);
upgradeModule.bootstrap(element).ready(() => {
expect(document.body.textContent).toEqual("ng1-NG2-ng1");
expect(document.body.textContent).toEqual("ng1[NG2(~ng-content~)]");
async.done();
});
}));