Search code examples
angularjsangular-ui-routerangular-componentsangular-controllerangular-data

UI Router, Passing Data From Parent Controller


I'm attempting to refactor a website into Angular through UI-Router. On the parent component I have defined some data on the controller. How do I pass this data to the child nested routed component through UI-Router? UI-Router's resolve only works when you have a binding on data, but I don't know if it's possible to bind the parent controller data to the parent component.

const main = angular.module('main', ['ui.router']);

main.config(function($stateProvider) {
  const states = [
      { name: 'parent', url: '/parent', component: 'parent' },
      { name: 'parent.child', url: '/{childUrl}', component: 'child',
        resolve: {
          data: function($transition$) {
            // I want to pass in { name: 'Name1', content: 'Page-Long Content1' }, { name: 'Name2', content: Page-Long Content2' }
            // How do I do this?
          }
        }
      }
    ];
    states.forEach(function(state) {
      $stateProvider.state(state);
    });
  });

angular.module('main')
  .component('parent', {
    template:
    '<div ng-repeat="data in $ctrl.data">' +
    '<p>{{data.name}}</p>' +
    '<a ui-sref="parent.child({ childUrl: data.name })" ui-sref-active="active">Child link</a>' +
    '</div>' +
    '<ui-view></ui-view>',

    controller: function() {
      this.data = [
        {name: 'Name1', content: 'Page-Long Content1'},
        {name: 'Name2', content: 'Page-Long Content2'}
      ]
    }
  });

angular.module('main')
  .component('child', {
    bindings: { data: '<' },
    templateUrl: 'link.html',
  });

Solution

  • Basically you have an unique identifier of your record in the URL. So by that you can retrieve your data once again from the dataset. For achieving the same, I'd suggest you to put your data in service and then fetch the same data in resolve of your state. Afterward apply an filter over the data and get desired record from it based on childUrl parameter of state.

    angular.module('main')
    .service('dataService', function(){
        var dataService = this;
        dataService.getData = getData;
        var data = [
            {name: 'Name1', content: 'Page-Long Content1'},
            {name: 'Name2', content: 'Page-Long Content2'}
        ];
    
        function getData(){
            return data;
        }
    
    });
    

    state

    const states = [
      { name: 'parent', url: '/parent', component: 'parent' },
      { name: 'parent.child', url: '/{childUrl}', component: 'child',
        resolve: {
          data: function($transition$, dataService) {
             let childUrl = $transition$.params('childUrl');
             //in case of API call below will be changed to promise driven code.
             return dataService.getData().filter((item) => item.name === childUrl)[0];
          }
        }
      }
    ];
    

    And inside a parent controller you can fetch data from service directly.

    controller: function(dataService) {
      this.data = dataService.getData();
    }