Router resolved data does not persist in ActivatedRoute data after navigation #12306

Closed
michaelchiche opened this Issue Oct 14, 2016 · 18 comments

Comments

Projects
None yet
5 participants
@michaelchiche
Contributor

michaelchiche commented Oct 14, 2016

I'm submitting a ... (check one with "x")

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior
The router resolved properties are not persisted inside the ActivatedRoute data unlike the data properties.

Expected behavior
The router resolved properties should be persisted inside the ActivatedRoute data like the data properties.

Minimal reproduction of the problem with instructions
http://plnkr.co/edit/twhzHaywqxVDPhD2R1NT?p=preview

What is the motivation / use case for changing the behavior?
Some motivations are:

  • Preload data application wide
  • Reuse preloaded data

Please tell us about your environment:

  • Angular version: 2.1.0

  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]

  • Language: [all | TypeScript X.X | ES6/7 | ES5]

  • Node (for AoT issues): node --version = v6.8.0

@michaelchiche michaelchiche changed the title from Router: router resolved data does not persist in ActivatedRoute data after navigation to Router resolved data does not persist in ActivatedRoute data after navigation Oct 14, 2016

@olegdunkan

This comment has been minimized.

Show comment
Hide comment
@olegdunkan

olegdunkan Oct 16, 2016

Contributor

@michaelchiche You can access this data through parent.
Try replace:

this.data = this.route.snapshot.data;

with this:

this.data = this.route.parent.snapshot.data;

You will get it all.

The real question is why when we first resolved data the data is flatted but when we go upward of url tree we must access data exactly at the node which defined it.

Contributor

olegdunkan commented Oct 16, 2016

@michaelchiche You can access this data through parent.
Try replace:

this.data = this.route.snapshot.data;

with this:

this.data = this.route.parent.snapshot.data;

You will get it all.

The real question is why when we first resolved data the data is flatted but when we go upward of url tree we must access data exactly at the node which defined it.

@michaelchiche

This comment has been minimized.

Show comment
Hide comment
@michaelchiche

michaelchiche Oct 16, 2016

Contributor

@olegdunkan What you say is true, but I am not looking for a hack. It works for simple routes, but what happens when I have 3 or more different nesting levels of children?

From what I understand, I am supposed to be able to access the data resolved after navigation inside the data property, which is not the case.

Contributor

michaelchiche commented Oct 16, 2016

@olegdunkan What you say is true, but I am not looking for a hack. It works for simple routes, but what happens when I have 3 or more different nesting levels of children?

From what I understand, I am supposed to be able to access the data resolved after navigation inside the data property, which is not the case.

@olegdunkan

This comment has been minimized.

Show comment
Hide comment
@olegdunkan

olegdunkan Oct 18, 2016

Contributor

@michaelchiche it is not hack, it is the way you can access data from parents, you can write simply function that go upward to any level. 'Parent' is a public property of route and snapshot. I didn't see any reasons do not use it. More then this it is the right way to get data from parents. How do you think to implement all data at all levels? Let say we have n levels and all levels resolves to data, in first level we have one property of data, next level adds one more, and finally we have n(n+1)/2 properties and n^2 complexity. Of course we can use prototyping but this is the same like parent property.

function getParentData(snapshot:any, level:number) {
  var ref = snapshot;

  while (level--) {
     ref = ref.parent;     
  }
  return ref.data;
}
Contributor

olegdunkan commented Oct 18, 2016

@michaelchiche it is not hack, it is the way you can access data from parents, you can write simply function that go upward to any level. 'Parent' is a public property of route and snapshot. I didn't see any reasons do not use it. More then this it is the right way to get data from parents. How do you think to implement all data at all levels? Let say we have n levels and all levels resolves to data, in first level we have one property of data, next level adds one more, and finally we have n(n+1)/2 properties and n^2 complexity. Of course we can use prototyping but this is the same like parent property.

function getParentData(snapshot:any, level:number) {
  var ref = snapshot;

  while (level--) {
     ref = ref.parent;     
  }
  return ref.data;
}
@michaelchiche

This comment has been minimized.

Show comment
Hide comment
@michaelchiche

michaelchiche Oct 18, 2016

Contributor

@olegdunkan: that's not the point... I am not asking how to do it...

I am filing a bug report because the documentation says that it is suppose to work without additional work.

Contributor

michaelchiche commented Oct 18, 2016

@olegdunkan: that's not the point... I am not asking how to do it...

I am filing a bug report because the documentation says that it is suppose to work without additional work.

@olegdunkan

This comment has been minimized.

Show comment
Hide comment
@olegdunkan

olegdunkan Oct 18, 2016

Contributor

@michaelchiche could you please give me the link where it is described in documentation?

Contributor

olegdunkan commented Oct 18, 2016

@michaelchiche could you please give me the link where it is described in documentation?

@michaelchiche

This comment has been minimized.

Show comment
Hide comment
@michaelchiche

michaelchiche Oct 18, 2016

Contributor

@olegdunkan: Are you being serious? if you don't know what you are talking about, please do not pollute the issue. thanks...

And for your information, it is said here: https://angular.io/docs/ts/latest/guide/router.html#!#activated-route

data: An Observable that contains the data object provided for the route. Also contains any resolved values from the resolve guard.

You can also check my plunker ;)

Contributor

michaelchiche commented Oct 18, 2016

@olegdunkan: Are you being serious? if you don't know what you are talking about, please do not pollute the issue. thanks...

And for your information, it is said here: https://angular.io/docs/ts/latest/guide/router.html#!#activated-route

data: An Observable that contains the data object provided for the route. Also contains any resolved values from the resolve guard.

You can also check my plunker ;)

@olegdunkan

This comment has been minimized.

Show comment
Hide comment
@olegdunkan

olegdunkan Oct 18, 2016

Contributor

The same question was asked at the vsavkin.com blog he answered that we have to use parent property.

It is what I want to say, how it works

{
    path: 'a',
    component:A,
    resolve: {
      A: AResolver // it is GOUARD not GOURDS
    },
    children: [
      {
        path: 'b',
        component:B,
        resolve: {
            B: BResolver  
        },
        children: [
        {
           path: 'c',
           component:C,
           resolve: {
               C: CResolver  
           }
        }
      }
    ]
  }


in A component 
onInit() {
  this.route.data.subscribe(data=> {
  //data = {A:...} 
  });
}

in B component 
onInit() {
  this.route.data.subscribe(data=> {
  //have to be data = {B:...}, not data = {A:.., B:..}
  });
  this.route.parent.data.subscribe(data=> {
  //data = {A:...}
  });
}

in C component 
onInit() {
  this.route.data.subscribe(data=> {
  //data = {C:...} 
  //have to be data = {C:...}, not data = {A:.., B:.., C:..}
  });
  this.route.parent.data.subscribe(data=> {
  //data = {B:...}
  });
  this.route.parent.parent.data.subscribe(data=> {
  //data = {A:...}
  });
}

I repeat the real question why you get data at first. It wouldn't be that way.

Documentation says common words you can't conclude exactly that data gathered from levels above.
Wait for officials what they will say.

Contributor

olegdunkan commented Oct 18, 2016

The same question was asked at the vsavkin.com blog he answered that we have to use parent property.

It is what I want to say, how it works

{
    path: 'a',
    component:A,
    resolve: {
      A: AResolver // it is GOUARD not GOURDS
    },
    children: [
      {
        path: 'b',
        component:B,
        resolve: {
            B: BResolver  
        },
        children: [
        {
           path: 'c',
           component:C,
           resolve: {
               C: CResolver  
           }
        }
      }
    ]
  }


in A component 
onInit() {
  this.route.data.subscribe(data=> {
  //data = {A:...} 
  });
}

in B component 
onInit() {
  this.route.data.subscribe(data=> {
  //have to be data = {B:...}, not data = {A:.., B:..}
  });
  this.route.parent.data.subscribe(data=> {
  //data = {A:...}
  });
}

in C component 
onInit() {
  this.route.data.subscribe(data=> {
  //data = {C:...} 
  //have to be data = {C:...}, not data = {A:.., B:.., C:..}
  });
  this.route.parent.data.subscribe(data=> {
  //data = {B:...}
  });
  this.route.parent.parent.data.subscribe(data=> {
  //data = {A:...}
  });
}

I repeat the real question why you get data at first. It wouldn't be that way.

Documentation says common words you can't conclude exactly that data gathered from levels above.
Wait for officials what they will say.

@DzmitryShylovich

This comment has been minimized.

Show comment
Hide comment
@DzmitryShylovich

DzmitryShylovich Oct 18, 2016

Contributor

I repeat the real question why you get data at first. It wouldn't be that way.

+1. that's the real issue

Contributor

DzmitryShylovich commented Oct 18, 2016

I repeat the real question why you get data at first. It wouldn't be that way.

+1. that's the real issue

@michaelchiche

This comment has been minimized.

Show comment
Hide comment
@michaelchiche

michaelchiche Oct 18, 2016

Contributor

@DzmitryShylovich @olegdunkan No.
And talking of vssavkin's blog. Here is what I want to do: https://vsavkin.com/the-powerful-url-matching-engine-of-angular-router-775dad593b03#7e93

In his gist, he shows how to share resolved data between child components... Look at the plunker please

Contributor

michaelchiche commented Oct 18, 2016

@DzmitryShylovich @olegdunkan No.
And talking of vssavkin's blog. Here is what I want to do: https://vsavkin.com/the-powerful-url-matching-engine-of-angular-router-775dad593b03#7e93

In his gist, he shows how to share resolved data between child components... Look at the plunker please

@DzmitryShylovich

This comment has been minimized.

Show comment
Hide comment
@DzmitryShylovich

DzmitryShylovich Oct 18, 2016

Contributor

http://plnkr.co/edit/NgDlGWjrMQC8pMVzSVkA?p=preview this is the correct plunker and expected behavior.

Did he write anything about data availability in his blog? No.

Contributor

DzmitryShylovich commented Oct 18, 2016

http://plnkr.co/edit/NgDlGWjrMQC8pMVzSVkA?p=preview this is the correct plunker and expected behavior.

Did he write anything about data availability in his blog? No.

@olegdunkan

This comment has been minimized.

Show comment
Hide comment
@olegdunkan

olegdunkan Oct 18, 2016

Contributor

@michaelchiche he (Victor) shows us how to share, not how to access data.
Access to resolved data has the same shape, via data property just so. If you define 'resolve' section in parent you have to get data from parent if you define section in parent parent please be patient and get it from parent parent.

Contributor

olegdunkan commented Oct 18, 2016

@michaelchiche he (Victor) shows us how to share, not how to access data.
Access to resolved data has the same shape, via data property just so. If you define 'resolve' section in parent you have to get data from parent if you define section in parent parent please be patient and get it from parent parent.

@michaelchiche

This comment has been minimized.

Show comment
Hide comment
@michaelchiche

michaelchiche Oct 18, 2016

Contributor

so can you explain why I can access the data defined in the data property of the parent without calling parent.data, but not the data inside the resolver, since, I repeat myself is supposed to be merged with data...

Contributor

michaelchiche commented Oct 18, 2016

so can you explain why I can access the data defined in the data property of the parent without calling parent.data, but not the data inside the resolver, since, I repeat myself is supposed to be merged with data...

@DzmitryShylovich

This comment has been minimized.

Show comment
Hide comment
@DzmitryShylovich

DzmitryShylovich Oct 18, 2016

Contributor

so can you explain why I can access the data defined in the data property of the parent without calling parent.data

it's the actual bug. and u have access only on initial navigation. or may be it's a feature. Need feedback from Victor

Contributor

DzmitryShylovich commented Oct 18, 2016

so can you explain why I can access the data defined in the data property of the parent without calling parent.data

it's the actual bug. and u have access only on initial navigation. or may be it's a feature. Need feedback from Victor

@michaelchiche

This comment has been minimized.

Show comment
Hide comment
@michaelchiche

michaelchiche Oct 18, 2016

Contributor

To my understanding, its the other way around.
Maybe @vsavkin can help us on this one? :)

Contributor

michaelchiche commented Oct 18, 2016

To my understanding, its the other way around.
Maybe @vsavkin can help us on this one? :)

@olegdunkan

This comment has been minimized.

Show comment
Hide comment
@olegdunkan

olegdunkan Oct 18, 2016

Contributor

@michaelchiche I have tried to explain you why data merge is not good idea and it seems to me that it is more likely bug then feature (n^2 to store all data) although for first navigation it is more likely feature. If it is a feature then every navigation along the path have to be accompanied with collection of data.

Let say we have a/b/c/d/e

Let first we navigate to a/b/c/d/e then at 'e' we will have all data (a/b/c/d, e) and it will cost nothing to get it because we go along the 'a', b', .. 'e' and we can preserve resolved data. But what if next navigation will be to a/b/c (upward) (we resolved a,b and c already we only need access to it)? Then to get {a,b,c} we have to keep it in 'c' node in merged form or collect it from a to c and get it to user. It is not necessary in many cases to have data from levels above at every level.
You have all(API) to get it through the parent property, it is your choice to use it or not.

Contributor

olegdunkan commented Oct 18, 2016

@michaelchiche I have tried to explain you why data merge is not good idea and it seems to me that it is more likely bug then feature (n^2 to store all data) although for first navigation it is more likely feature. If it is a feature then every navigation along the path have to be accompanied with collection of data.

Let say we have a/b/c/d/e

Let first we navigate to a/b/c/d/e then at 'e' we will have all data (a/b/c/d, e) and it will cost nothing to get it because we go along the 'a', b', .. 'e' and we can preserve resolved data. But what if next navigation will be to a/b/c (upward) (we resolved a,b and c already we only need access to it)? Then to get {a,b,c} we have to keep it in 'c' node in merged form or collect it from a to c and get it to user. It is not necessary in many cases to have data from levels above at every level.
You have all(API) to get it through the parent property, it is your choice to use it or not.

@olegdunkan

This comment has been minimized.

Show comment
Hide comment
@olegdunkan

olegdunkan Oct 18, 2016

Contributor

@michaelchiche I will try to check it. By the way, if we have the same name of data properties at different levels then how conflicts will be resolved?

{
    path: 'a',
    component:A,
    resolve: {
      part: AResolver 
    },
    children: [
      {
        path: 'b',
        component:B,
        resolve: {
            part: BResolver  
        }
      }
    ]
  }


in B component 
onInit() {
  this.route.data.subscribe(data=> {
  // => data = {part:...}); //from AResolver or BResolver, last??????
}

It is difficult to maintain

Contributor

olegdunkan commented Oct 18, 2016

@michaelchiche I will try to check it. By the way, if we have the same name of data properties at different levels then how conflicts will be resolved?

{
    path: 'a',
    component:A,
    resolve: {
      part: AResolver 
    },
    children: [
      {
        path: 'b',
        component:B,
        resolve: {
            part: BResolver  
        }
      }
    ]
  }


in B component 
onInit() {
  this.route.data.subscribe(data=> {
  // => data = {part:...}); //from AResolver or BResolver, last??????
}

It is difficult to maintain

@olegdunkan

This comment has been minimized.

Show comment
Hide comment
@olegdunkan

olegdunkan Oct 18, 2016

Contributor

@michaelchiche
I have checked it, look at https://github.com/angular/angular/blob/2.1.0/modules/%40angular/router/src/router.ts#L728
these lines say us that router reusing path and do not add checks (CanActivate for routes we have passed).

Contributor

olegdunkan commented Oct 18, 2016

@michaelchiche
I have checked it, look at https://github.com/angular/angular/blob/2.1.0/modules/%40angular/router/src/router.ts#L728
these lines say us that router reusing path and do not add checks (CanActivate for routes we have passed).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment