2

I have a hybrid angular-cli that roughly follows Victor Savkin's Lazy Loaded AngularJS guide. AngularJS is bootstraped in the constructor of a LazyLoaded Angular module. The main difference between my app and the guide is that I am trying to wrap the <ui-view> directive inside of some Angular components. Because of how my layout is structured the <ui-view> element will not be available when AngularJS is bootstrapped and may be added or removed at any time.

import { Component, Directive, ElementRef, Injector } from '@angular/core';
import { UpgradeComponent } from '@angular/upgrade/static';
import * as angular from 'angular';

@Component({
  template: `
  <layout-wrapper>
    <my-toolbar></my-toolbar>
    <layout-contents>
      <ng2-ui-view>
        <h3 class="text-center">AngularJS page not loaded</h3>
      </ng2-ui-view>
    </layout-contents>
  </layout-wrapper>
  `,
})
export class LegacyOutputComponent { }

@Directive({selector: 'ng2-ui-view'})
export class UpgradedUiViewComponent extends UpgradeComponent {
  constructor(ref: ElementRef, inj: Injector) {
    super('uiViewWrapper', ref, inj);
  }
}

export const routerPatchModule = 'arcs.router.patch';

// We need to define a wrapper for ui-view because we can only upgrade
// components with only one definition. uiView cannot be automatically
// upgraded because its definition is too complex
angular.module(routerPatchModule, ['ui.router'])
.component('uiViewWrapper', { template: '<ui-view></ui-view>'})

When I run the code a Error: No provider for $scope! error is thrown. Checking the stack trace I can see that it is thrown in the UpgradeComponent super class. The injector tries to get $scope and

2 Answers 2

6

Alternative is to let Angular know that it needs to provide the $scope.

import { Injector } from '@angular/core';

// allow $scope to be provided to ng1
export const ScopeProvider = {
  deps: ['$injector'],
  provide: '$scope',
  useFactory: (injector: Injector) => injector.get('$rootScope').$new(),
};

@Directive({
  providers: [ ScopeProvider ],
  selector: 'ng2-ui-view',
})
export class UpgradedUiViewComponent extends UpgradeComponent {
  constructor(ref: ElementRef, inj: Injector) {
    super('uiViewWrapper', ref, inj);
  }
}

Sign up to request clarification or add additional context in comments.

Comments

1

This setup will not work. AngularJS needs to be able to load in the root of your application in order for the scope to be defined correctly.

A better way to approach this problem is to use the <div ui-view> directive in the root of your application (as in the upgrade guide) and then to downgrade a layout component from Angular into AngularJS to wrap your content.

1 Comment

Vizjerai's suggestion still applies to resolve runtime 'NullInjectorError: No provider for $scope!' browser error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.