Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nested ui-view error #2763

Closed
Luddinus opened this issue May 21, 2016 · 12 comments
Closed

nested ui-view error #2763

Luddinus opened this issue May 21, 2016 · 12 comments
Labels
Milestone

Comments

@Luddinus
Copy link

Hi.

I have nested view like this

<div ui-view="main">
   <div ui-view="content"></div>
</div>

And this routes

   $stateProvider.state('main', {
        url: '/',
        controller: 'MainController as main',
        template: require('./main.html')
    });

     $stateProvider.state('main.profile', {
        url: 'profile',
        views: {
            'content': {
                controller: 'ProfileController as profile',
                template: require('./profile.html')
            }
        }
    });

And I get this error: Cannot read property 'name' of undefined
at getUiViewName

I'm using 0.3 version...

What Am I missing?

@christopherthielen
Copy link
Contributor

christopherthielen commented May 21, 2016

is require() happening synchronously somehow? Generally require() means AMD, which is async. template: wouldn't work with async function. That's the first thing I noticed in your code.

Can you try switching to templateUrl: './profile.html' etc and see what happens?

@Luddinus
Copy link
Author

It worked with previous version I think.

I changed this way and it works, I'll try more things later

<div ui-view>
   <div ui-view="content"></div>
</div>

@christopherthielen
Copy link
Contributor

if you can reproduce the error code in a plunker, I'd be happy to take a look

http://bit.ly/UIR-Plunk

@homerjam
Copy link

Hi @christopherthielen

I've also noticed this issue - would appreciate any thoughts: http://plnkr.co/edit/tYl0WK?p=preview

Thanks!

@MWallenberg
Copy link

This started showing up in my application as well. It started when updating from 0.2.18 to 0.3. I'm not sure what causes it yet, but will post back here if I manage to figure it out.

@egantz
Copy link

egantz commented May 30, 2016

Hey, joining the gang. I am also experiencing this issue and I do and templateUrl in each route config.

Any ideas?

@MWallenberg
Copy link

I downgraded to the previous legacy versiom for now - then it works again.
Den 30 maj 2016 3:42 em skrev "Eyal Gantz" [email protected]:

Hey, joining the gang. I am also experiencing this issue and I do and
templateUrl in each route config.

Any ideas?


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#2763 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AEydyvjIPYWS1x1hKf9c9tFILuLqGM6qks5qGulWgaJpZM4Ijqjv
.

@christopherthielen
Copy link
Contributor

introduced by this commit fde64e1

@christopherthielen christopherthielen added this to the 0.3.1 milestone May 30, 2016
@christopherthielen
Copy link
Contributor

@Luddinus @homerjam @MWallenberg @egantz

I've figured out what's causing this bug; before 0.3.0 the element.data('$uiView', data) didn't happen until the $ViewDirectiveFill was linked. Now, it happens earlier; when the $ViewDirective is linked. The Fill directive is walking up the DOM looking for inherited $uiView data on the elements, and finding the not-yet-filled copy of the parent ui-view, which doesn't have a state applied yet.

I'll figure out how to fix this bug.


In the meantime, can you explain why you'd create a nested ui-view like this?

<div ui-view="main">
   <div ui-view="content"></div>
</div>

This makes no sense to me.

Also, the original bug report's state definition doesn't seem to match the reported HTML:

// unnamed view has nowhere to plug into???
$stateProvider.state('main', {
        template: require('./main.html')

...

     $stateProvider.state('main.profile', {
        views: {
            'content': {

Can somebody explain what the intention is of this setup?

@homerjam
Copy link

homerjam commented Jun 2, 2016

Great thanks @christopherthielen.

I realise this structure looks a bit weird but its a simplification of a setup I've used quite a few times. However I started doing this a couple of years ago so maybe its no longer necessary to do so. I'll try and dig out my original rationale from my memory.

One use case is to provide a simple way to resolve app-wide dependencies - I can do this by adding them to an abstract parent state definition which uses the main view - then any child states will have access to those dependencies. This also allows me to have a sibling view (beside content) such as a menu which remains constant across the app but requires data from the server to render for the first time.

I think another reason it helps to do it like this is for when pre-rendering the app for SEO - its easier to ensure you have everything loaded as there is a distinct structure to follow.

Aren't nested views pretty handy in general anyway (or is it specifically this setup that seems unusual)? Do you have any thoughts on a better solution?

@christopherthielen
Copy link
Contributor

christopherthielen commented Jun 2, 2016

@homerjam nested views are certainly useful. The plunker's specific setup (a single template with a nested ui-view inside of an outer ui-view) is weird. Generally a template has one ui-view, or multiple sibling ui-views.

<ui-view name="main">
  <ui-view name="content">
  </ui-view>
</ui-view>

When a state's view fills in the "main" ui-view, the inner html is replaced by the new template (the "content" ui-view is then gone) and so the "content" view cannot be targeted anymore. On the other hand, if a state doesn't fill in the "main" ui-view, so it can instead fill the "content" ui-view, then what's the point of the "main" view?


This makes sense to me:

<ui-view name="main">
</ui-view>
<ui-view name="content">
</ui-view>

This also makes sense to me:

<ui-view name="main">
</ui-view>

.state('main', {
  views: { 
    main: { template: "<ui-view name="content"></ui-view>" }
  }
})

.state('main.child', {
  views: { 
    content: { template: '<h1>content</h1>' } 
  } 
});

@homerjam
Copy link

homerjam commented Jun 2, 2016

@christopherthielen I understand - primarily I striped the plunker back to basics to demonstrate the issue. Your examples make more sense in a real world scenario however. Thanks again for looking into this.

christopherthielen added a commit that referenced this issue Jun 3, 2016
The `$uiView` element.data lifecycle is somewhat fragile. The Fill directive reads the inherited `$uiView` data to figure out which state the ui-view was created in.  In a previous commit, the non-fill directive was setting the `$uiView` date earlier to hold the animation promises.  This caused the fill directive to read the wrong state data, breaking some users' apps.

BC-BREAK Users who were using `element.data('$uiView').$animEnter` or `$animLeave` should now use `element.data('$uiViewAnim').$animEnter` instead

Closes #2763
christopherthielen added a commit that referenced this issue Aug 31, 2016
The `$uiView` element.data lifecycle is somewhat fragile. The Fill directive reads the inherited `$uiView` data to figure out which state the ui-view was created in.  In a previous commit, the non-fill directive was setting the `$uiView` date earlier to hold the animation promises.  This caused the fill directive to read the wrong state data, breaking some users' apps.

BC-BREAK Users who were using `element.data('$uiView').$animEnter` or `$animLeave` should now use `element.data('$uiViewAnim').$animEnter` instead

Closes #2763

Manually merged/cherry picked from commit d3502f3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants