Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@angular/router not working inside an angular.js application

I'm working on migrating little by little a big angular.js application (that uses ui-router) to angular and I opted by using the angular.js application as a base and migrate the different routes one at a time so that once I'm finished I switch everything at once to angular.

These are the steps I've followed:

Bootstap the angular.js application in my main.ts file:

export function bootstrapAngular(extra: StaticProvider[]): any {
  setAngularJSGlobal(angular);
  if (environment.production) {
    enableProdMode();
  }
  return platformBrowserDynamic(extra)
    .bootstrapModule(AppModule)
    .catch(err => console.log(err));
}

const downgraded = angular
  .module('downgraded', [downgradeModule(bootstrapAngular)])
  .directive('appRoot', downgradeComponent({ component: RootComponent, propagateDigest: false }))
  ;

angular.bootstrap(document, ['app', downgraded.name]);

Inside my index.html

<app id="app"></app>

This works fine.

Inside my main angular.js component I add the tag of my downgraded main Angular component:

<div class="app__view" id="appContent">
  <ui-view></ui-view>
  <app-root></app-root>
</div>

This is how my main module is configured

const COMPONENTS = [
  TestComponent,
  RootComponent,
];

@NgModule({
  declarations: COMPONENTS,
  imports: [
    BrowserModule,
    NxModule.forRoot(),
    RouterModule.forRoot(routes, {
      initialNavigation: 'enabled',
      useHash: true
    })
  ],
  providers: [
    { provide: APP_BASE_HREF, useValue: '/' }
  ],
  entryComponents: COMPONENTS,
  exports: COMPONENTS
})
export class AppModule {
  ngDoBootstrap(): void { }
}

Everything works fine so far. I can see my angular component inside my angular.js application.

The problem comes when I add the to my main root component I can see the router-outlet rendering but nothin next to it, eventhough the route matches.

export const routes: Route[] = [
  { path: 'dashboard', component: TestComponent }
];

When I point my browser to /#/dashboard this is the router tracing that I see:

router tracing

And the test component just doesn't render.

enter image description here

I need some help, can't think of anything else to try.

like image 850
curial Avatar asked Sep 06 '18 07:09

curial


People also ask

Why routing is not working in AngularJS?

The problem is the default hash-prefix used for $location hash-bang URLs is ('! ') that's why there are additional unwanted characters in your URL. If you actually want to have no hash-prefix and make your example work then you can remove default hash-prefix (the '!'

Is router mandatory for all applications in Angular?

simple answer is, no. It is not mandatory to have routes defined on every component you create.


1 Answers

First of all: if you want to go hybrid and start moving parts of ng1 to ngx, you need to bootstrap your ng1 app from ngx as you did, but not by downgrading:

platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
  (<any>platformRef.instance).upgrade.bootstrap(document.body, ['nameOfNg1App']);
});

Than you should provide the entry point for ui-router within your app.component.html:

<div ui-view></div>

You also need to provide an url handling strategy to tell angular, which routes to handle. I had an AppRoutingModule, which was imported by the AppModule. And this one provided the handler:

@NgModule({
  imports  : [
    RouterModule.forRoot(routes, {useHash: true})
  ],
  exports  : [
    RouterModule
  ],
  // provide custom UrlHandlingStrategy to separate AngularJs from Angular routes
  providers: [
    {
      provide : UrlHandlingStrategy,
      useClass: Ng1Ng2UrlHandlingStrategy
    }
  ]
})
export class AppRoutingModule {
}

And the Handling strategy, I used path prefixes to separate ng1 from ngx routes, but you can choose a simpler separation if needed:

import { UrlHandlingStrategy } from '@angular/router';

export class Ng1Ng2UrlHandlingStrategy implements UrlHandlingStrategy {
    private ng1Urls: string[];

    constructor() {
        this.ng1Urls = [
            'prefix1',
        ];
    }

    shouldProcessUrl(url) {
        url = url.toString();
        return this.ng1Urls.findIndex(ng1Url => new RegExp(`^\/${ng1Url}([|\?|\/](.*)){0,1}$`).test(url)) === -1;
    }

    extract(url) {
        return url;
    }

    merge(url, whole) {
        return url;
    }
}

Oh, and for some reasons I had to stick to # URLs, while running hybrid.

With this setup you start an ngx app, that has a container that runs the ui-router. Within your ng1 app you can then use downgraded ngx components and services. To have ngx-routes and ng1 routes in parallel, your (ngx) app.component.html consists of

<div ui-view></div>
<router-outlet></router-outlet>

You find more details of this strategy here: https://blog.nrwl.io/upgrading-angular-applications-upgrade-shell-4d4f4a7e7f7b

like image 91
André Avatar answered Sep 29 '22 02:09

André