1

Using Angular UI Router, I'm trying to render a different component based on a $state.params value, but I can't find a clean way to do this.

I figured out a working solution already (with some ES2015 fanciness), but that's far from optimal:

/* ----- chapter/chapter.controller.js ----- */
class ChapterController {

  constructor($state) {
    this.$state = $state;
    this.chapterNb = this.$state.params.chapterNb;
  }

}

ChapterController.$inject = ['$state'];

export default ChapterController;

/* ----- chapter/chapter.controller.js ----- */
import controller from './chapter.controller';

const ChapterComponent = {
  controller,
  template: `
    <chapter-01 ng-if="$ctrl.chapterNb === 1"></chapter-01>
    <chapter-02 ng-if="$ctrl.chapterNb === 2"></chapter-02>
  ` // and more chapters to come...
};

export default ChapterComponent;

/* ----- chapter/index.js ----- */
import angular from 'angular';
import uiRouter from 'angular-ui-router';

import ChaptersComponent from './chapters.component';
import ChaptersMenu from './chapters-menu';
import Chapter from './chapter';

const chapters = angular
  .module('chapters', [
    uiRouter,
    ChaptersMenu,
    Chapter
  ])
  .component('chapters', ChaptersComponent)
  .config($stateProvider => {
    'ngInject';
    $stateProvider
      .state('chapters', {
        abstract: true,
        url: '/chapters',
        component: 'chapters'
      })
      .state('chapters.menu', {
        url: '/menu',
        component: 'chaptersMenu'
      })
      .state('chapters.chapter', {
        url: '/{chapterNb:int}',
        component: 'chapter'
      });
  })
  .name;

export default chapters;

The thing is that every <chapter-0*> component is very different, that's why they all correspond to their own template. I would like to find a way to reference automatically the chapter component corresponding to the $state.params.chapterNb instead of having to write those ng-if for each one.

Is there any way to simplify this? Or maybe there is a specific feature for that purpose?

2 Answers 2

1

I think you could do something like below, if you aren't passing any data to component.

const ChapterComponent = {
  controller,
  template: ($state) => {
     return ['<chapter-', $state.chapterNb, '></chapter-', $state.chapterNb, '>'].join("")
  }
};

Other way is you could maintain separate template for each chapter & have some URL convention. Thereafter you could render those template using either templateUrl function of component or ng-include directive with src.

Sign up to request clarification or add additional context in comments.

3 Comments

@ClementParis016 does it helped you?
Hey sorry I was working on something else, but yes, your help was pretty useful, thank you! I'm going to post the working solution as an answer ;)
@ClementParis016 the thing which you are using is just tweak in string concatenation, as you are using interpolation in template, thats it, Thanks :)
0

As suggested by Pankaj Parkar in his answer, using a template function helps here.

With a few tweaks, I've been able to achieve loading the correct component based on $state.params, so here is my solution, for the record (look at first post for others files involved):

import controller from './chapter.controller';

const ChapterComponent = {
  controller,
  template: ($state) => {
    'ngInject';
    return `
      <chapter-0${$state.params.chapterNb}></chapter-0${$state.params.chapterNb}>
    `;
  }
};

export default ChapterComponent;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.