UpgradeAdapter

Stable Class

Class Overview

class UpgradeAdapter {
  constructor(ng2AppModule: Type<any>)
  
  
  downgradeNg2Component(type: Type<any>) : Function
  upgradeNg1Component(name: string) : Type<any>
  bootstrap(element: Element, modules?: any[], config?:IAngularBootstrapConfig) : UpgradeAdapterRef
  upgradeNg1Provider(name: string, options?: {asToken: any})
  downgradeNg2Provider(token: any) : Function
}

Class Description

Use UpgradeAdapter to allow AngularJS v1 and Angular v2 to coexist in a single application.

The UpgradeAdapter allows:

  1. creation of Angular v2 component from AngularJS v1 component directive (See [UpgradeAdapter#upgradeNg1Component()])
  2. creation of AngularJS v1 directive from Angular v2 component. (See [UpgradeAdapter#downgradeNg2Component()])
  3. Bootstrapping of a hybrid Angular application which contains both of the frameworks coexisting in a single application.

Mental Model

When reasoning about how a hybrid application works it is useful to have a mental model which describes what is happening and explains what is happening at the lowest level.

  1. There are two independent frameworks running in a single application, each framework treats the other as a black box.
  2. Each DOM element on the page is owned exactly by one framework. Whichever framework instantiated the element is the owner. Each framework only updates/interacts with its own DOM elements and ignores others.
  3. AngularJS v1 directives always execute inside AngularJS v1 framework codebase regardless of where they are instantiated.
  4. Angular v2 components always execute inside Angular v2 framework codebase regardless of where they are instantiated.
  5. An AngularJS v1 component can be upgraded to an Angular v2 component. This creates an Angular v2 directive, which bootstraps the AngularJS v1 component directive in that location.
  6. An Angular v2 component can be downgraded to an AngularJS v1 component directive. This creates an AngularJS v1 directive, which bootstraps the Angular v2 component in that location.
  7. Whenever an adapter component is instantiated the host element is owned by the framework doing the instantiation. The other framework then instantiates and owns the view for that component. This implies that component bindings will always follow the semantics of the instantiation framework. The syntax is always that of Angular v2 syntax.
  8. AngularJS v1 is always bootstrapped first and owns the bottom most view.
  9. The new application is running in Angular v2 zone, and therefore it no longer needs calls to $apply().

Example

var adapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
var module = angular.module('myExample', []);
module.directive('ng2Comp', adapter.downgradeNg2Component(Ng2));

module.directive('ng1Hello', function() {
  return {
     scope: { title: '=' },
     template: 'ng1[Hello {{title}}!](<span ng-transclude></span>)'
  };
});


@Component({
  selector: 'ng2-comp',
  inputs: ['name'],
  template: 'ng2[<ng1-hello [title]="name">transclude</ng1-hello>](<ng-content></ng-content>)',
  directives:
})
class Ng2Component {
}

@NgModule({
  declarations: [Ng2Component, adapter.upgradeNg1Component('ng1Hello')],
  imports: [BrowserModule]
})
class MyNg2Module {}


document.body.innerHTML = '<ng2-comp name="World">project</ng2-comp>';

adapter.bootstrap(document.body, ['myExample']).ready(function() {
  expect(document.body.textContent).toEqual(
      "ng2[ng1[Hello World!](transclude)](project)");
});

Constructor

constructor(ng2AppModule: Type<any>)

Class Details

downgradeNg2Component(type: Type<any>) : Function

Allows Angular v2 Component to be used from AngularJS v1.

Use downgradeNg2Component to create an AngularJS v1 Directive Definition Factory from Angular v2 Component. The adapter will bootstrap Angular v2 component from within the AngularJS v1 template.

Mental Model

  1. The component is instantiated by being listed in AngularJS v1 template. This means that the host element is controlled by AngularJS v1, but the component's view will be controlled by Angular v2.
  2. Even thought the component is instantiated in AngularJS v1, it will be using Angular v2 syntax. This has to be done, this way because we must follow Angular v2 components do not declare how the attributes should be interpreted.

Supported Features

  • Bindings:
    • Attribute: <comp name="World">
    • Interpolation: <comp greeting="Hello {{name}}!">
    • Expression: <comp [name]="username">
    • Event: <comp (close)="doSomething()">
  • Content projection: yes
var adapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
var module = angular.module('myExample', []);
module.directive('greet', adapter.downgradeNg2Component(Greeter));

@Component({
  selector: 'greet',
  template: '{{salutation}} {{name}}! - <ng-content></ng-content>'
})
class Greeter {
  @Input() salutation: string;
  @Input() name: string;
}

@NgModule({
  declarations: [Greeter],
  imports: [BrowserModule]
})
class MyNg2Module {}

document.body.innerHTML =
  'ng1 template: <greet salutation="Hello" [name]="world">text</greet>';

adapter.bootstrap(document.body, ['myExample']).ready(function() {
  expect(document.body.textContent).toEqual("ng1 template: Hello world! - text");
});
upgradeNg1Component(name: string) : Type<any>

Allows AngularJS v1 Component to be used from Angular v2.

Use upgradeNg1Component to create an Angular v2 component from AngularJS v1 Component directive. The adapter will bootstrap AngularJS v1 component from within the Angular v2 template.

Mental Model

  1. The component is instantiated by being listed in Angular v2 template. This means that the host element is controlled by Angular v2, but the component's view will be controlled by AngularJS v1.

Supported Features

  • Bindings:
    • Attribute: <comp name="World">
    • Interpolation: <comp greeting="Hello {{name}}!">
    • Expression: <comp [name]="username">
    • Event: <comp (close)="doSomething()">
  • Transclusion: yes
  • Only some of the features of Directive Definition Object are supported:
    • compile: not supported because the host element is owned by Angular v2, which does not allow modifying DOM structure during compilation.
    • controller: supported. (NOTE: injection of $attrs and $transclude is not supported.)
    • `controllerAs': supported.
    • `bindToController': supported.
    • `link': supported. (NOTE: only pre-link function is supported.)
    • `name': supported.
    • `priority': ignored.
    • `replace': not supported.
    • require: supported.
    • restrict: must be set to 'E'.
    • scope: supported.
    • template: supported.
    • templateUrl: supported.
    • terminal: ignored.
    • transclude: supported.
var adapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
var module = angular.module('myExample', []);

module.directive('greet', function() {
  return {
    scope: {salutation: '=', name: '=' },
    template: '{{salutation}} {{name}}! - <span ng-transclude></span>'
  };
});

module.directive('ng2', adapter.downgradeNg2Component(Ng2));

@Component({
  selector: 'ng2',
  template: 'ng2 template: <greet salutation="Hello" [name]="world">text</greet>'
})
class Ng2 {
}

@NgModule({
  declarations: [Ng2, adapter.upgradeNg1Component('greet')],
  imports: [BrowserModule]
})
class MyNg2Module {}

document.body.innerHTML = '<ng2></ng2>';

adapter.bootstrap(document.body, ['myExample']).ready(function() {
  expect(document.body.textContent).toEqual("ng2 template: Hello world! - text");
});
bootstrap(element: Element, modules?: any[], config?:IAngularBootstrapConfig) : UpgradeAdapterRef

Bootstrap a hybrid AngularJS v1 / Angular v2 application.

This bootstrap method is a direct replacement (takes same arguments) for AngularJS v1 bootstrap method. Unlike AngularJS v1, this bootstrap is asynchronous.

var adapter = new UpgradeAdapter();
var module = angular.module('myExample', []);
module.directive('ng2', adapter.downgradeNg2Component(Ng2));

module.directive('ng1', function() {
  return {
     scope: { title: '=' },
     template: 'ng1[Hello {{title}}!](<span ng-transclude></span>)'
  };
});


@Component({
  selector: 'ng2',
  inputs: ['name'],
  template: 'ng2[<ng1 [title]="name">transclude</ng1>](<ng-content></ng-content>)'
})
class Ng2 {
}

@NgModule({
  declarations: [Ng2, adapter.upgradeNg1Component('ng1')],
  imports: [BrowserModule]
})
class MyNg2Module {}

document.body.innerHTML = '<ng2 name="World">project</ng2>';

adapter.bootstrap(document.body, ['myExample']).ready(function() {
  expect(document.body.textContent).toEqual(
      "ng2[ng1[Hello World!](transclude)](project)");
});
upgradeNg1Provider(name: string, options?: {asToken: any})

Allows AngularJS v1 service to be accessible from Angular v2.

class Login { ... }
class Server { ... }

@Injectable()
class Example {
  constructor(@Inject('server') server, login: Login) {
    ...
  }
}

var module = angular.module('myExample', []);
module.service('server', Server);
module.service('login', Login);

var adapter = new UpgradeAdapter();
adapter.upgradeNg1Provider('server');
adapter.upgradeNg1Provider('login', {asToken: Login});
adapter.addProvider(Example);

adapter.bootstrap(document.body, ['myExample']).ready((ref) => {
  var example: Example = ref.ng2Injector.get(Example);
});

downgradeNg2Provider(token: any) : Function

Allows Angular v2 service to be accessible from AngularJS v1.

class Example {
}

var adapter = new UpgradeAdapter();
adapter.addProvider(Example);

var module = angular.module('myExample', []);
module.factory('example', adapter.downgradeNg2Provider(Example));

adapter.bootstrap(document.body, ['myExample']).ready((ref) => {
  var example: Example = ref.ng1Injector.get('example');
});

exported from @angular/upgrade/index, defined in @angular/upgrade/src/upgrade_adapter.ts

doc_Angular
2016-10-06 09:47:09
Comments
Leave a Comment

Please login to continue.