Search code examples
angularrouterangular-routerangular4-router

how to storing route params in nested routes in angular 4?


reason of using nested route for me is handling dynamically icon and back button for every page.i have abstract route because when i click to back button route params disappear and i put an abstract path to keep id and questionnaire type parameter in url.my abstract path is Questionaire.

      const routes: Routes = [
          {
             path: '',
              component: LayoutComponent, 
            children:[
              { path: 'Home', component: HomeComponent,data:{icon:'fa-home'} },
              { path: 'QuestionaireList', component: QuestionaireListComponent,data:{icon:'fa-list-ul',previousState:'/Home'} },
              { path: 'ModifyMetaContent/:metaContentId/:title', component: ModifyMetaContentComponent,data:{icon:'fa-database',previousState:'/MetaContentList'}}

              { 
                path: 'Questionaire/:id',
                children:[
                { path: 'MetaContentList', component: MetaContentListComponent,data:{icon:'fa-database',previousState:'/QuestionaireList'}}

      ]},




              { 
                path: 'Questionaire/:questionnaireType',
              children:
              [     
                 { path: 'AddQuestionnaire', component: CreateQuestionnaireComponent,data:{icon:'fa-plus',previousState:'/QuestionaireList'}},      
              ]},
              { 
              path: 'Questionaire/:questionnaireType/:id',
              children:[ 
              { path: 'UpdateQuestionnaire', component: EditComponent,data:{icon:'fa-pencil',previousState:'/QuestionaireList'}  },
              { path: 'QuestionList', component: QuestionListComponent,data:{icon:'fa-pencil',previousState:'/QuestionaireList'} },
              { path: 'ImportQuestion',    component: ImportQuestionComponent,data:{icon:'fa-plus',previousState:'/QuestionaireList'}   },

            ]} ,
            ]},
      ];

MetaContentList.Component.html

   <a class="ui labeled positive icon small button" [routerLink]="['/ModifyMetaContent','',questionnaireTitle]">
  <i class="plus icon"></i>
 new metaContent
</a>

i store previous url in snapshot.data.previousState but when i click to ModifyMetaContent i go to

localhost:4200/ModifyMetaContent/...

and when i click to back button , id and questionnairetype disappear from url.when i to click to ModifyMetaContent i expected go to :

localhost:4200/Questionaire/b8b55b42-f39f-4359-93d0-0260ddf3827f/MetaContentList/ModifyMetaContent/...

and when i click to back button i expected go to

.../Questionaire/b8b55b42-f39f-4359-93d0-0260ddf3827f/MetaContentList/ but url set to localhost:4200/MetaContentList

and this error occurred :

Cannot match any routes. URL Segment: 'MetaContentList'

i handle this case by nested states of angularjs ui-router.is any solution to this issue in angular2+ router ?


Solution

  • i solve this issue by change route structure and add a function for previousstate link in appcomponent:

    my router:

        const routes: Routes = [
          {
             path: '',
              component: LayoutComponent, 
                children:[
              { path: 'Home', component: HomeComponent,data:{icon:'fa-home',previousState:[]} },
              { path: 'QuestionaireList', component: QuestionaireListComponent,data:{icon:'fa-list-ul',previousState:['/Home']} },
    
              { path: 'Questionaire/:id',children:[
                { path: 'MetaContentList', component: MetaContentListComponent,data:{icon:'fa-database',previousState:['/QuestionaireList']}},
                { path: 'ModifyMetaContent/:metaContentId/:title', component: ModifyMetaContentComponent,data:{icon:'fa-database',previousState:['Questionaire','MetaContentList']}}
                ]},
              { path: 'Questionaire/:questionnaireType',
                children:[{ path: 'AddQuestionnaire', component: CreateQuestionnaireComponent,data:{icon:'fa-plus',previousState:['/QuestionaireList']}}]},
              {path: 'Questionaire/:questionnaireType/:id',
                children:[ 
              { path: 'UpdateQuestionnaire', component: EditComponent,data:{icon:'fa-pencil',previousState:['/QuestionaireList']}  },
              { path: 'QuestionList', component: QuestionListComponent,data:{icon:'fa-pencil',previousState:['/QuestionaireList']} },
              { path: 'ImportQuestion',    component: ImportQuestionComponent,data:{icon:'fa-upload',previousState:['/QuestionaireList']}   },
            ]} ,
            ]},      
      ];
    

    in my router 2 state is possible :

    1. previous url is normal
    2. previous url is nested url for implementation above state i put previousstate in an array if we are at state 2 array.length is bigger than 1 .for embedding route params i create a method in appcomponent:

    method for get lastchild :

     getSnapshot(route: ActivatedRoute){
                    let lastChild = route;
                    while (lastChild.firstChild) {
                    lastChild = lastChild.firstChild;
                    }
                    return lastChild;
                    } 
    

    method for get previous state :

    getPreviousUrl(a):string{
      let previousState:string;
      const previousStateLength=a.snapshot.data.previousState ? a.snapshot.data.previousState.length :null;
      if(previousStateLength!==null){
       if(previousStateLength<=1 )
       {previousState=a.snapshot.data.previousState[0];}
       else{
         previousState='/';
         let parentParams=[''];
         let j:number=0;
         let b=a;
         while(b.parent){
           b.parent.params.subscribe((params)=>{
             Object.keys(params).map(key=>parentParams[j]+=params[key]+'/');
             for(let i=0;i<previousStateLength-1;i++){
               if(parentParams[j]!==undefined)
               previousState+=a.snapshot.data.previousState[i]+'/'+parentParams[j];
             }
            })
           b=b.parent;
         j++;
         }
         previousState+=a.snapshot.data.previousState[previousStateLength-1];
    
       }
       return previousState;
      }
    
    }
    

    and get data :

    constructor(router:Router,route:ActivatedRoute) {
    
         router.events
         .filter(event => event instanceof NavigationEnd)
    
         .subscribe(e => {
    
           const lastChild=this.getSnapshot(route);
           this.routerIcon = lastChild.snapshot.data.icon;
           this.previousState=this.getPreviousUrl(lastChild);
    
       });
    

    its work for me bu i want to maximality improve it.