Skip to content

'$locationShim': Not a valid '@angular/upgrade' application. #46211

Closed

Description

@vzakharov-rxnt

Description

I'm getting issues implementing ngUpgrade according to the official docs.
I am at the stage when everything works, except navigation from Angular 1 to Angular 13.
It is not clear from the docs where this code should be put:

angular.module('rxntBillingApp')
          .factory('$location', downgradeInjectable($locationShim));

I tried putting it before app.bootstrap(el) in LazyLoaderService, but this results in an error:

lazy-loader.service.ts:21 Error: Error while instantiating injectable '$locationShim': Not a valid '@angular/upgrade' application. Did you forget to downgrade an Angular module or include it in the AngularJS application?

This is a valid angular upgrade application because when this $locationShim downgrade is removed, everything works fine. The reason to introduce location shim is to unify routing, so that AngularJS application can route back to Angular 13 app.

It's not very clear from the docs, but I changed this.upgrade.bootstrap inside app.module.ts to bootstrap a regular AppComponent, which then has <router-outlet> and routes to Angular 13 test component or to AngularJS component which lazily loads all the static assets and performs the bootstrap.

// app-routing.module.ts
export const routes: Routes = [
  // Routes rendered by Angular
  { path: 'test-component', component: TestComponent },

  // AngularJS routes
  { path: '**', component: AngularJSComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
// angular-js.component.ts
export class AngularJSComponent implements OnInit, OnDestroy {
  constructor(
    private lazyLoader: LazyLoaderService,
    private elRef: ElementRef
  ) {}

  ngOnInit() {
    this.lazyLoader.load(this.elRef.nativeElement);
  }

  ngOnDestroy() {
    this.lazyLoader.destroy();
  }
}

And here is the code for LazyLoaderService, which is following the official example:

import { Injectable } from '@angular/core';
import angular from 'angular';
import { downgradeInjectable } from '@angular/upgrade/static';
import { $locationShim } from '@angular/common/upgrade';

@Injectable({
  providedIn: 'root'
})
export class LazyLoaderService {
  private app: angular.auto.IInjectorService | undefined;

  load(el: HTMLElement): void {
    import(/* webpackChunkName: "main.legacy" */ '../../app/index').then(app => {
      try {
        angular.module('rxntBillingApp')
          .factory('$location', downgradeInjectable($locationShim));  // tried adding this code:
        
        this.app = app.bootstrap(el);
      } catch (e) {
        console.error(e);
      }
    });
  }

  destroy() {
    if (this.app) {
      this.app.get('$rootScope').$destroy();
    }
  }
}

app.bootstrap code is as follows:

export function bootstrap(el: HTMLElement) {
  return angular.bootstrap(el, ['rxntBillingApp']);  
}

Please advise if you can see anything wrong with the above implementation.

What is the affected URL?

https://angular.io/guide/upgrade#using-the-unified-angular-location-service

Please provide the steps to reproduce the issue

No response

Please provide the expected behavior vs the actual behavior you encountered

No response

Please provide a screenshot if possible

No response

Please provide the exception or error you saw

No response

Is this a browser-specific issue? If so, please specify the device, browser, and version.

No response

Activity

  1. vzakharov-rxnt commented on Jun 1, 2022

    @vzakharov-rxnt
    Author

    I realized that by changing this.upgrade.bootstrap to app.bootstrap, it is no longer considered an ngUpgrade application. So for example downgradeComponent also fails, meaning the issue is not specific to $locationShim.

    Now, problem with this.upgrade.bootstrap is that it does not return anything, so I cannot assign the result to this.app, in order for destroy function to run correctly, according to the docs. Still not sure if I am on the right track, I'll continue the investigation.

  2. gkalpak commented on Jun 1, 2022

    @gkalpak
    Member

    You are right that you cannot use things like downgradeInjectable() if you do not bootstrap the app with UpgradeModule#bootstrap() (since it will not be a hybrid, ngUpgrade app).

    It would definitely make sense to have UpgradeModule#bootstrap() return the AngularJS injector to align with angular.bootstrap(). In the meantime, you can use the AngularJS injector via UpgradeModule#$injector (after the app has been bootstrapped with UpgradeModule#bootstrap()).

  3. vzakharov-rxnt commented on Jun 1, 2022

    @vzakharov-rxnt
    Author

    @gkalpak Can you give an example with source code, or a link to it?

    This doesn't look like valid JS/TS syntax:

    [UpgradeModule#$injector][3]
    
  4. added
    area: upgradeIssues related to AngularJS → Angular upgrade APIs
    on Jun 1, 2022
  5. added this to the needsTriage milestone on Jun 1, 2022
  6. gkalpak commented on Jun 1, 2022

    @gkalpak
    Member

    Sorry, it was supposed to be a Markdown link. I fixed my comment.

  7. vzakharov-rxnt commented on Jun 1, 2022

    @vzakharov-rxnt
    Author

    @gkalpak Are you saying this:

    this.app.get('$rootScope').$destroy();
    

    should be changed to this

    this.upgrade.$injector.get('$rootScope').$destroy();
    

    ?

  8. gkalpak commented on Jun 1, 2022

    @gkalpak
    Member

    Something like that. upgrade.$injector could be undefined (for example, if you haven't bootstrapped an AngularJS app yet), so you could have something like: this.upgrade.$injector?.get('$rootScope').destroy()

  9. vzakharov-rxnt commented on Jun 2, 2022

    @vzakharov-rxnt
    Author

    @gkalpak Thank you, George. Please update the official docs when you can, this section:

  10. angular-automatic-lock-bot commented on Jul 4, 2022

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  11. locked and limited conversation to collaborators on Jul 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: upgradeIssues related to AngularJS → Angular upgrade APIs

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions