Thursday 11 July 2019

javascript - Share data from parent to child state with Angular UI-router



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:





A person!


Name: {{student_name}}

Id: {{student_id}}





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?


Answer



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:




A person!


{{student}}

Name: {{student_name}}

Id: {{student_id}}





here is why I prefer to use resolve and its advantages


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...