How to fix multiple ng-view divs being added in Angular Hybrid app?

I have set up an AngularJS/Angular hybrid app by following Angular’s Upgrade Guide and Viktor Savkin’s Upgrade Series, in an attempt to migrate a huge legacy code-base. I’ve added a new route to this application which will use an Angular component, and I’m using new Angular Router alongside ngRoute from the AngularJS app.

Everything works (Angular Component used inside AngularJS template and some new URLs fully operating on Angular Components), except for this minor and very annoying problem – if I open the home-page of my application, I cannot use any route managed by ngRoute and all the routes managed by Angular Router keep showing the template of the home-page.


Here’s how the code looks like (all paths from the src directory of project-root):

ng2/app.component.html

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

ng2/app.component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
   constructor(private upgrade: UpgradeModule) { }

    ngOnInit() {
      this.upgrade.bootstrap(document.documentElement, ['app']);
    }
}

ng2/app.module.ts

declare var angular: any;

export class CustomHandlingStrategy implements UrlHandlingStrategy {
  shouldProcessUrl(url) {
    return url.toString().startsWith("/ng") || url.toString() == "/"
  }
  extract(url) { return url; }
  merge(url, whole) { return url; }
}

angular.module('app')
  .directive(
    'new-component',
    downgradeComponent({component: NewComponent})
  );

@NgModule({
  declarations: [
    AppComponent,
    Ng2DemoComponent
  ],
  imports: [
    BrowserModule,
    UpgradeModule,
    RouterModule.forRoot([
      {
        path: 'ng/newroute',
        component: NewComponent
      }
    ],
    {
      useHash: true,
      initialNavigation: true,
      enableTracing: true
    })
  ],
  entryComponents: [
    NewComponent
  ],
  providers: [
    { provide: UrlHandlingStrategy, useClass: CustomHandlingStrategy }
  ],
  bootstrap: [AppComponent]
})

export class AppModule {
}

ng1/app.routes.js

var app = angular.module('app',[
  'ngRoute'
]);
app.config(['$routeProvider',function($routeProvider){
   $routeProvider
   .when('/', {
     templateUrl:'home/home.component.html'
   }).
   .when('/phone-list', {
     templateUrl:'phoneList/phoneList.component.html'
   });
}]);

index.html

<html lang="en">
     .
     .
     .
   <body ng-controller="rootController"> 
        <a href="#/phones"></a>
        <a routerLink="ng/newroute">New Component</a>
        <app-root></app-root>
     .
    </body>

On opening the home-page of the application, the home-page renders correctly – but following any link has the following effects:

  • If the link points to an old URL (#/phones in the example), the address changes in the address-bar, but the new HTML is not rendered. A new <div ng-view> gets appended with every click on any such link. In the Console, there’s an error saying Cannot read property 'nativeNode' of null.
  • If the link points to a new URL (ng/newroute in the example), it renders the expected HTML, but does NOT hide the mark-up of home.component.html.

On starting with any other page (like directly visiting the #/phones page by typing it in the address-bar), each link works exactly as it is supposed to be.

Solutions tried so far

  • Adding a sink-route in either or both of the routing-logic – doing this in either of them stops the other completely.

Am I missing something ?

Source: AngularJS