1

Based on this tutorial, I have as my parent state a list of people. When I click on one of them, a new view is created in order to show the details for that person. In my URL I use the ID for that person, so it's rather easy to go and fetch the ID to be used in the child state. The problem is that I also want to pass information such as the name, e-mail, age, etc.

The code is as follows:

My routes:

angular
    .module('appRoutes', ["ui.router"])
    .config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {


    var TalentForceState_seeProfile = {
      name: 'students',
      url: '/seeProfile',
      templateUrl: 'public/templates/talentforce_template.html',
      controller: 'People_Controller'
    }

    var singleStudent = { 
      name: 'student',
      parent: 'students',
      url: '/:personId',
      templateUrl: 'public/templates/person_template.html',
      controller: 'Person_Controller'
    }

 ....

Then, the controller for People:

talentforceApp
    .controller('People_Controller', ['$scope', '$state', '$stateParams', 'StudentService', function($scope, $state, $stateParams, StudentService) {

        StudentService.query().$promise.then(function(data) {
            $scope.students = data;
        });

}]);

Then, the controller for Person:

talentforceApp
    .controller('Person_Controller', ['$scope', '$state', '$stateParams', 'StudentService', function($scope, $state, $stateParams, StudentService) {

$scope.student_id = $stateParams.personId;
console.log($stateParams)
}]);

Also, here's the HTML for the Person:

<div ng-controller="Person_Controller">
    <h3>A person!</h3>
        <div>Name: {{student_name}}</div>
        <div>Id: {{student_id}}</div>
    <button ui-sref="students">Close</button>
</div>

Information such as student_name is what I can't seem to pass from the parent state

I tried using solutions like this, that use $state.go, or this, that use params, but it always gives me errors such as param values not valid for state or the variables are undefined.

Any solution for this problem?

Community
  • 1
  • 1
Shoplifter.Doe
  • 118
  • 4
  • 16

2 Answers2

4

You can use angular's state resolve to achieve your requirement in a better way. Although there are many choices for it.

Procedure:

  1. When your parent state loads, you query all the people in an API call.
  2. In that response, I am assigning the response to an instance of a service using studentService.addStudents($scope.students); where addStudents is a function in the service.
  3. Now, when you navigate to the detail of a person, I have used resolve which fetches the stored data from the service using the function studentService.getStudents() and returns a person object to the controller.
  4. Use that person object directly in the person controller by injecting the resolve variable

I prefer using resolve. I will tell you why.

Here is the resolve you can use:

resolve: {
    student: function(studentService, $stateParams) {
      return studentService.getStudents().find(function(student) { 
        return student.id === $stateParams.personId;
      });
    }
  }

You will add a service studentService or you can extend your own service.

Service:

talentforceApp.service('studentService', function(){
  vm = this;
  vm.students = []

   this.addStudents = function(students) {
      vm.students = students;
   }

   this.getStudents = function() {
      return vm.students;
   }
});

I added addStudents and getStudents methods to it.

One method add students to array and the other get the data of a studenr.

People Controller revised:

talentforceApp
    .controller('People_Controller', ['$scope', '$state', '$stateParams', 'StudentService', function($scope, $state, $stateParams, StudentService,studentService) {

        StudentService.query().$promise.then(function(data) {
            $scope.students = data;
            studentService.addStudents($scope.students); // this will create a students array in service instance
        });
}]);

I assigned $scope.students to the service instance.

routes revised:

var TalentForceState_seeProfile = {
  name: 'students',
  url: '/seeProfile',
  templateUrl: 'public/templates/talentforce_template.html',
  controller: 'People_Controller'
}

var singleStudent = { 
  name: 'student',
  parent: 'students',
  url: '/:personId',
  templateUrl: 'public/templates/person_template.html',
  controller: 'Person_Controller',
  resolve: {
    student: function(studentService, $stateParams) {
      return studentService.getStudents.find(function(student) { 
        return student.id === $stateParams.personId;
      });
    }
  }
}

Now, you can use student from resolve into your controller, as a dependency.

person controller revised:

talentforceApp
    .controller('Person_Controller', ['$scope', '$state', '$stateParams', 'StudentService',student, function($scope, $state, $stateParams, StudentService,student) {
    $scope.student_id = $stateParams.personId;
    console.log($stateParams)
    $scope.student = student // this line add student to scope
    console.log($scope.student)
}]);

Check your student object in the view:

View:

<div ng-controller="Person_Controller">
    <h3>A person!</h3>
         {{student}}
        <div>Name: {{student_name}}</div>
        <div>Id: {{student_id}}</div>
    <button ui-sref="students">Close</button>
</div>

here is why I prefer to use resolve and its advantages

Sravan
  • 18,467
  • 3
  • 30
  • 54
  • It gives out `student` as undefined – Shoplifter.Doe Jan 30 '17 at 16:01
  • also, it says `Error: [$injector:unpr] Unknown provider: studentProvider <- student <- Person_Controller` – Shoplifter.Doe Jan 30 '17 at 16:07
  • I resolved it. There was a conflict between the declared controllers. There is no need to declare the `ng-controller="Person_Controller"` in the div, since the binding between the template and the controller is already done in the state. – Shoplifter.Doe Jan 30 '17 at 18:54
  • Yes it is. Thank you. – Shoplifter.Doe Jan 31 '17 at 10:05
  • There are few change you need to incorporate after angular 1.6 release.. Resolved parameters will not be available directory in controller. Instead you need to extend `$onInit` as described in https://toddmotto.com/angular-1-6-is-here#component-and-oninit – kushdilip Feb 13 '17 at 13:42
0

You can't pass a large object with nested properties with $state.go. You can use event: broadcast, emit. Creating a service that hold and share data to your controllers is a better way.

Faly
  • 13,291
  • 2
  • 19
  • 37