agon024 agon024 - 4 months ago 15
Javascript Question

Inserting JSON ID key into ng-click directive and then pass that into another controller

This section of the app shows the minimal information of a user's task. When they click the "view details" button it will take them to a page that has more information about that specific CAR based on is ID.

Here is a pic to help explain the first part of what I am talking about:

enter image description here

Here is my angular code: EDIT - Added ui-router code

angular.module('ngApp', ['ui.router'])
.factory('authInterceptor', authInterceptor)
.constant('API', 'http://myserver.com/ecar/api')
.controller('task', taskData)
.controller('carDetails', carDetails)
.controller('myCars', myCars)

// ** EDIT ** ADDED MY UI-ROUTER CODE
.config(function($httpProvider, $stateProvider, $urlRouterProvider){

$urlRouterProvider.otherwise('/cars');

$stateProvider

.state('cars', {
url: '/cars',
templateUrl: 'cars.html'
})

.state('carDetails', {
url: '/carDetails',
templateUrl: 'mycar_details.html',
controller: 'carDetails'
})

.state('taskDetails', {
url: '/taskDetails',
templateUrl: 'task_details.html',
controller: 'taskData'
})
)}

function carDetails($scope, $http, API) {
$http.get( API + '/car/**THE CAR ID**' ).
success(function(data) {
$scope.details = data;
console.log(data);
});
}


EDIT - Button HTML:

<a ng-click="" ui-sref="carDetails">View Details</a>


As you can see each CAR has its own unique ID (of course). I can display the ID by using:

ng-repeat="task in mainTask.Tasks"

{{ task['CAR ID'] }} // in the html


But I need this to do two things:


  1. When the user clicks the View button I need it to take them to another page titled car_details.html. That page will make use of the "carDetails" controller which will display all the info for the CAR.

  2. When a user clicks that same button I need somehow to take that specific ID of that CAR ( {{ task['CAR ID'] }} ) being displayed in that tile and then somehow pass it to the carDetails function in the spot that says:

    $http.get( API + '/car/THE CAR ID' )



Where "THE CAR ID' needs to have the ID passed to it of the CAR who's "view details" button was just clicked. So that when the car_details.html page opens it will have all the correct content loaded for that car.

EDIT - The routes work good in the main html file with ui-view. But I just cant figure out how to pass the unique ID from each of the tiles JSON ID key when their respective "view details" button is clicked.

I hope I have been clear enough. Let me know if I haven't and I will try to give you more info.

Thanks for the help!

Answer

There are 2 commonly accepted ways (that I know of) to handle this. The first, most popular, and most highly recommended way is to use a service or factory. The other is to use the router and routeParams to pass the ID of the card to the details controller.

I have no idea how you plan on displaying your details page (either using the router to navigate to a new page, or a directive to simply hide/show some hidden DOM elements), but a service/factory can be used in BOTH situations, where as the routeParams can only be used in one.

(I also highly recommend you follow, as closely as possible, the angular style guide here: https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md if you want to save yourself a lot of headaches)

angular.module('ngApp', [])
.service('CarDetailService', CarDetailService)
.controller('task', taskData)
.controller('carDetails', carDetails);

CarDetailService.$inject = ['$http', 'API'];
function CarDetailService($http, API) {
  var CarDetailService = this;
  CarDetailService.setCar = function(carId) {
    CarDetailService.carId = carId;
  };

  CarDetailService.getCar = function() {
    return $http.get(API + "/car/" + CarDetailService.carId);
  };
}

taskData.$inject = ['$scope', '$http', 'API', 'CarDetailService'];
function taskData($scope, $http, API, CarDetailService) {
  $http.get( API + '/tasks' ).
  success(function(data) {
    $scope.mainTask = data;
    console.log(data);
  });

  $scope.selectCar = function(carId) {
    CarDetailService.setCar(carId);
    $location.url('/car-details-route');  //go to details page
  };
}

carDetails.$inject = ['$scope', 'CarDetailService'];
function carDetails($scope, CarDetailService) {
  CarDetailService.getCar().success(function(details) {
    $scope.details = details;
  });
}

And your ng-repeat would look somthing like this:

<div ng-repeat="task in mainTask.tasks" ng-click="selectCar(task['Car ID'])">
  {{task['Car ID']}}
</div>

The service is a singleton, meaning that the id will persist through route changes and controller existences.

The other way, is to use $routeParams. The docs for that are here: https://docs.angularjs.org/api/ngRoute/service/$routeParams

$routeParams allows you to add your ID into the path which is read by the router and passed to the controller:

angular.module('ngApp', []).config(function($routeProvider) {

  $routeProvider.when('/car-details-route/:carId', {
    controller: 'carDetails',
    templateUrl: 'car-details.html'
  });

})
.controller('task', taskData)
.controller('carDetails', carDetails);


taskData.$inject = ['$scope', '$location'];
function taskData($scope, $location) {
  $http.get( API + '/tasks' ).
  success(function(data) {
    $scope.mainTask = data;
    console.log(data);
  });

  $scope.selectCar = function(carId) {
    $location.path('/car-details-route/'+carId); 
  };
}

carDetails.$inject = ['$scope', 'API', '$routeParams'];
function carDetails($scope, API, $routeParams) {
  $http.get(API + "/cars/" + $routeParams.carId).success(function(details) {
    $scope.details = details;
  });
}