angular-hybrid icon indicating copy to clipboard operation
angular-hybrid copied to clipboard

Error when routing Angular 4 components into nested AngularJS ui-views

Open mischkl opened this issue 7 years ago • 12 comments

Affects the following combination of packages: @ui-router/angular-hybrid 3.1.2 angular 4.3 angularjs 1.5 typescript 2.3

Description: We have the following app structure:

    <ui-view name="left-menu-outer">
        <ui-view name="left-menu"></ui-view>
    </ui-view>
    <ui-view name="content">
        <ui-view name="center"></ui-view>
        <ui-view name="right"></ui-view>
    </ui-view>

This worked fine with AngularJS components and Angular 4 components that we manually downgraded to AngularJS and registered with the AngularJS $stateRegistry using @uirouter/angularjs v1.0.

Now we are attempting to use @ui-router/angular-hybrid to ease the migration, so that we no longer have to manually downgrade our NG4 components. For simple top-level routing to either left-menu-outer or content this works fine, using either the feature module approach (@NgModule({imports: [UIRouterModule.forChild({states: MY_STATES})]})) or by registering with $stateRegistry. However, when targeting nested ui-views, for instance the following:

{
    name: 'app.showcase',
    url: '/showcase',
    views: {
        'left-menu': {
            component: ShowcaseLeftMenuComponent
        },
        'center': {
            component: ShowcaseComponent
        }
    }
},

the app crashes with the following messages:

angular.js:14199 Error: ViewDestroyedError: Attempt to use a destroyed view: detectChanges
    at viewDestroyedError (core.es5.js:8445)
    at Object.debugUpdateRenderer [as updateRenderer] (core.es5.js:13093)
    at checkAndUpdateView (core.es5.js:12243)
    at callViewAction (core.es5.js:12603)
    at execComponentViewsAction (core.es5.js:12535)
    at checkAndUpdateView (core.es5.js:12244)
    at callWithDebugContext (core.es5.js:13458)
    at Object.debugCheckAndUpdateView [as checkAndUpdateView] (core.es5.js:12998)
    at ViewRef_.detectChanges (core.es5.js:10169)
    at static.es5.js:282
(anonymous) @ angular.js:14199
$delegate.(anonymous function) @ log.interceptor.ts:33
(anonymous) @ angular.js:10707
$digest @ angular.js:17854
$apply @ angular.js:18102
(anonymous) @ angular.js:26597
dispatch @ jquery.js:4737
elemData.handle @ jquery.js:4549
ZoneDelegate.invokeTask @ zone.js:424
onInvokeTask @ core.es5.js:3881
ZoneDelegate.invokeTask @ zone.js:423
Zone.runTask @ zone.js:191
ZoneTask.invokeTask @ zone.js:498
invokeTask @ zone.js:1370
globalZoneAwareCallback @ zone.js:1388
angular.js:14199
TypeError: Cannot read property '$$nextSibling' of null
    at Scope.$digest (angular.js:17864)
    at ChildScope.$apply (angular.js:18102)
    at HTMLAnchorElement.<anonymous> (angular.js:26597)
    at HTMLAnchorElement.dispatch (jquery.js:4737)
    at HTMLAnchorElement.elemData.handle (jquery.js:4549)
    at ZoneDelegate.invokeTask (zone.js:424)
    at Object.onInvokeTask (core.es5.js:3881)
    at ZoneDelegate.invokeTask (zone.js:423)
    at Zone.runTask (zone.js:191)
    at ZoneTask.invokeTask [as invoke] (zone.js:498)
(anonymous) @ angular.js:14199
$delegate.(anonymous function) @ log.interceptor.ts:33
(anonymous) @ angular.js:10707
$apply @ angular.js:18104
(anonymous) @ angular.js:26597
dispatch @ jquery.js:4737
elemData.handle @ jquery.js:4549
ZoneDelegate.invokeTask @ zone.js:424
onInvokeTask @ core.es5.js:3881
ZoneDelegate.invokeTask @ zone.js:423
Zone.runTask @ zone.js:191
ZoneTask.invokeTask @ zone.js:498
invokeTask @ zone.js:1370
globalZoneAwareCallback @ zone.js:1388
core.es5.js:1020
ERROR Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.5.11/$rootScope/inprog?p0=%24digest
    at angular.js:68
    at beginPhase (angular.js:18357)
    at Scope.$digest (angular.js:17785)
    at static.es5.js:1324
    at SafeSubscriber.schedulerFn [as _next] (core.es5.js:3647)
    at SafeSubscriber.__tryOrUnsub (Subscriber.js:238)
    at SafeSubscriber.next (Subscriber.js:185)
    at Subscriber._next (Subscriber.js:125)
    at Subscriber.next (Subscriber.js:89)
    at EventEmitter.Subject.next (Subject.js:55)
defaultErrorLogger @ core.es5.js:1020
ErrorHandler.handleError @ core.es5.js:1080
next @ core.es5.js:4503
schedulerFn @ core.es5.js:3635
SafeSubscriber.__tryOrUnsub @ Subscriber.js:238
SafeSubscriber.next @ Subscriber.js:185
Subscriber._next @ Subscriber.js:125
Subscriber.next @ Subscriber.js:89
Subject.next @ Subject.js:55
EventEmitter.emit @ core.es5.js:3621
(anonymous) @ core.es5.js:3912
ZoneDelegate.invoke @ zone.js:391
Zone.run @ zone.js:141
NgZone.runOutsideAngular @ core.es5.js:3844
onHandleError @ core.es5.js:3912
ZoneDelegate.handleError @ zone.js:395
Zone.runTask @ zone.js:194
ZoneTask.invokeTask @ zone.js:498
invokeTask @ zone.js:1370
globalZoneAwareCallback @ zone.js:1388

The last error ($digest already in progress) is repeated approximately 50 times. The errors occur regardless of the contents of the routed components and regardless of whether the states were registered using the feature module approach or $stateRegistry.

Expected behavior: The Angular 4 component should be able to be routed into the nested ui-view, the same as with AngularJS components.

mischkl avatar Aug 01 '17 17:08 mischkl

Check out Limitations, maybe you can find something useful there:

We currently support routing either Angular (2+) or AngularJS (1.x) components into an AngularJS (1.x) ui-view. However, we do not support routing AngularJS (1.x) components into an Angular (2+) ui-view.

If you create an Angular (2+) ui-view, then any nested ui-view must also be Angular (2+). Because of this, apps should be migrated starting from leaf states/views and work up towards the root state/view

claudiuconstantin avatar Aug 11 '17 10:08 claudiuconstantin

@claudiuconstantin all of our ui-views are defined in Angular 1... at no point are we attempting to route an Angular 1 component into an Angular 2 ui view

mischkl avatar Aug 11 '17 10:08 mischkl

@christopherthielen any chance you have an idea what the problem could be? Could it be that we need to restructure our ui-views to accomodate the hybrid routing? We'd be very thankful for any assistance!

mischkl avatar Aug 23 '17 09:08 mischkl

@claudiuconstantin do you think these limitations of routing ng 1.x views into a 2 + view will ever be lifted and supported?

httpete avatar Nov 14 '17 21:11 httpete

@mischkl Did you ever get this working? I'm am also currently migrating an Angular.js app using ui-router to Angular 2+ and would like to support nested ui-views.

princetoncollins avatar Apr 30 '20 21:04 princetoncollins

@claudiuconstantin I think I may be in the same boat as @mischkl. However it's not clear to me if the limitations of @uirouter/angular-hybrid also include Angular 2 components that have been downgraded.

For example... in my Angular.js app I've created some Angular 2 components that have been downgraded. I'm routing to these downgraded components using Angular.js ui-router(via angular-hybrid). If one of these downgraded components I'm routing to has it's own <div ui-view></div> in it's template, will this ui-view not be supported?

princetoncollins avatar Apr 30 '20 21:04 princetoncollins

It's been a long time since I've looked at this stuff. I think if you're only routing a downgraded ng2 component into an ng1 ui-view then you may not need the angular-hybrid module. IIRC, nested ng1 ui-view should work fine even if there is a downgraded ng2 component in the middle.

christopherthielen avatar Apr 30 '20 22:04 christopherthielen

@christopherthielen Thanks for the quick reply. So, I've been able to route to an downgraded ng2 component in an ng1 ui-view okay.

However, if the downgraded ng2 component itself has another ui-view in it, I can't seem to target it in order to display other content.

Example below:

<div class="width-100">
  <!-- uiView: -->
  <div ui-view="" class="ng-scope"> // Root UI-View here
    <engagement-app class="ng-scope" ng-version="8.2.14"> // The downgraded ng2 component.
       <ui-view> // The downgraded ng2 component's ui-view.
          <!---->
          <!--bindings={
              "ng-reflect-ng-if": "true"
           }-->
          <!---->
       </ui-view>
    </engagement-app>
  </div>
</div>

The inner ui-view which I previously named "main", with the intention of targeting it by name, is the one I'm trying to render content inside. I don't know if this is possible, mainly because the <engagement-app> component is a downgraded ng2 component, and so the it's nested ui-view won't work with the ng1 state config?

@christopherthielen I'd appreciate your insight concerning this, and I apologize that this a very old issue. Just wondering if what I'm attempting to accomplish is possible.

And if if I need @ui-router/angular-hybrid to do it.

princetoncollins avatar Apr 30 '20 23:04 princetoncollins

oh so the downgraded component engagement-app has an ng2 template which contains <ui-view>?

That will never render an AngularJS <ui-view> because Angular templates render Angular components. You could possibly create an AngularJS component that renders an AngularJS <ui-view> and then upgrade that to ng2.

// upgrade this component to ng2
angularjsmodule.component('uiViewWrapper', {
  template: '<ui-view></ui-view>'
});
<div class="width-100">
  <!-- uiView: -->
  <div ui-view="" class="ng-scope"> // Root AngularJS UI-View here
    <engagement-app class="ng-scope" ng-version="8.2.14"> // The downgraded ng2 component.
      <ui-view-wrapper> // The upgraded-to-ng2 AngularJS component which renders an AngularJS ui-view.
       <ui-view> 
       </ui-view>
      </ui-view-wrapper>
    </engagement-app>
  </div>
</div>

FWIW, all the uirouter hybrid projects assume each view rendered from one component framework will render a ui-view using that same component framework. Basically migrate views from the leafs up towards the root. What you're doing is violating that assumption, but you may be able to use the above workaround. Warning: there be dragons here.

christopherthielen avatar May 01 '20 03:05 christopherthielen

@christopherthielen Thanks for the info. I do my best to steer clear of dragons, if I can. I ended up changing the <ui-view/> in the downgraded ng2 component, <engagement-app /> , to a <router-outlet></router-outlet>.

Breaking it down, I have, My root ng1 <ui-view/> rendering the downgraded ng2 component, <engagement-app/>. ...and the <engagement-app/> only renders a <router-outlet></router-outlet> which is where I want to render other ng2 components.

<div class="width-100">
  <!-- uiView: -->
  <div ui-view="" class="ng-scope"> // Root AngularJS UI-View here
    <engagement-app class="ng-scope" ng-version="8.2.14"> // The downgraded ng2 component.
      <router-outlet></router-outlet>
    </engagement-app>
  </div>
</div>

Currently the router-outlet is not working. I get the <engagement-app/>, and I can see the <router-outlet/> inside of it, but nothing rendered inside of that router-outlet. I'm not getting any errors either, I should also mention the ng2 components I want to render in the are currently still downgraded. Would that be a problem?

princetoncollins avatar May 01 '20 04:05 princetoncollins

Sounds like you're now mixing ui-router and the Angular Router. I know that's a thing people have done before, but I don't know the details. If you search, I'm sure you'll find some blogs that explain how to mix those two technologies. Sorry, I really can't be of much help when it comes to the Angular Router as I've never used it.

christopherthielen avatar May 01 '20 16:05 christopherthielen

@mischkl Did you ever get this working? I'm am also currently migrating an Angular.js app using ui-router to Angular 2+ and would like to support nested ui-views.

As mentioned, we simply had to stick with the "solution" of not using the hybrid router and downgrading all routable Angular components to AngularJS. Eventually we got fed up and moved towards a gradual migration strategy to the Angular router (keeping strictly separated routes depending on the feature area and technology), after having migrated most components. Obviously more work in the short term but in the end run it seems better maintained and documented than ui-router.

mischkl avatar May 01 '20 21:05 mischkl

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. This does not mean that the issue is invalid. Valid issues may be reopened. Thank you for your contributions.

stale[bot] avatar Nov 12 '22 11:11 stale[bot]