Yacub Ali
Yacub Ali

Reputation: 137

Passing JSON value from one Controller to another

I am trying to pass a JSON string value that is stored in one controller to another. I am using a custom service to pass the data, but it doesn't seem to be passing the value.

The First controller where the JSON string value is stored:

filmApp.controller('SearchController',['$scope', '$http','$log','sharedService',function($scope,$http,$log,sharedService){

    $scope.results = {
      values: []
    };
    var vm = this;
    vm.querySearch   = querySearch;
    vm.searchTextChange = searchTextChange;
    vm.selectedItemChange = selectedItemChange;

 function querySearch(query) {
   return $http.get('https://api.themoviedb.org/3/search/movie?include_adult=false&page=1&primary_release_year=2017', {
         params: { 
             'query': query,
             'api_key': apiKey
         }
  }).then(function(response) {
       var data = response.data.results.filter(function(obj) {
        return obj.original_title.toLowerCase().indexOf(query) != -1;
    })
    return data;

        for (var i = 0; i < data.results.length; i++) {
           $scope.results.values.push({title: data.results[i].original_title});
           // $log.info($scope.results.values);   
       }
       return $scope.results.values;
    })
};


function searchTextChange(text) {
    // $log.info('Search Text changed to ' + text);
}

function selectedItemChange(item) {
 $scope.value = JSON.stringify(item);
    return sharedService.data($scope.value);
}

}]);

The custom Angular service - The value is received here:

filmApp.service('sharedService',function($log){
  vm = this;
  var value = [];
   vm.data = function(value){
      $log.info("getValue: " + value); // received value in log
          return value;
    }
});

The Second controller that wants to receive the JSON value from the First controller:

filmApp.controller('singleFilmController',['$scope', '$http','$log','sharedService',function($scope,$http,$log,sharedService){

var value = sharedService.data(value);
 $log.info("Data: " + value);

}]);

The value is received in the service but the second controller can't seem to access it. Not sure why it is happening as I'm returning the value from the data() method from the service. Also, the selectedItemChange method is used by the md-autocomplete directive.

Upvotes: 2

Views: 245

Answers (3)

Aluan Haddad
Aluan Haddad

Reputation: 31853

Technically, you can resolve this by simply changing your service definition to

(function () {
  'use strict';

  SharedService.$inject = ['$log'];
  function SharedService($log) {
    var service = this;
    var value = [];
    service.data = function (value) {
      $log.info("getValue: " + value); // received value in log
        service.value = value;
        return service.value;
    };
  });

  filmApp.service('SharedService', SharedService);
}());

But it is a very poor practice to inject $http directly into your controllers. Instead, you should have a search service that performs the queries and handle the caching of results in that service.

Here is what that would like

(function () {
  'use strict';

  search.$inject = ['$q', '$http'];
  function search($q, $http) {
    var cachedSearches = {};
    var lastSearch;
    return {
      getLastSearch: function() {
        return lastSearch;
      },
      get: function (query) {
        var normalizedQuery = query && query.toLowerCase();
        if (cachedSearches[normalizedQuery]) {
          lastSearch = cachedSearches[normalizedQuery];
          return $q.when(lastSearch);
        }

        return $http.get('https://api.themoviedb.org/3/search/movie?' + 
            'include_adult=false&page=1&primary_release_year=2017', {
          params: {
            query: query,
            api_key: apiKey
          }
        }).then(function (response) {
          var results = response.data.results.filter(function (result) {
            return result.original_title.toLowerCase().indexOf(normalizedQuery) !== -1;
          }).map(function (result) {
            return result.original_title;
          });

          cachedSearches[normalizedQuery] = results;

          lastSearch = results;

          return results;
        }
      });
    }

  }

  filmApp.factory('search', search);

  SomeController.$inject = ['$scope', 'search'];
  function SomeController($scope, search) {
    $scope.results = [];

    $scope.selectedItemChange = function (item) {
      $scope.value = JSON.stringify(item);

      return search.get($scope.value).then(function (results) {
        $scope.results = results;
      });
    }
  }

  filmApp.controller('SomeController', SomeController);
}());

It is worth noting that a fully fledged solution would likely work a little differently. Namely it would likely incorporate ui-router making use of resolves to load the details based on the selected list item or, it could equally well be a hierarchy of element directives employing databinding to share a common object (nothing wrong with leveraging two-way-binding here).

It is also worth noting that if I were using a transpiler, such as TypeScript or Babel, the example code above would be much more succinct and readable.

Upvotes: 1

SDSMTKyzer
SDSMTKyzer

Reputation: 112

I'm pretty new to AngularJS but I'm pretty sure all you are doing is two distinct function calls. The first controller passes in the proper value, the second one then overwrites that with either null or undefined

I usually use events that I manually fire and catch on my controllers. To fire to sibling controllers, use $rootScope.$emit()

In the other controller then, you would catch this event using a $rootscope.$on() call

This article helped me a decent amount when I was working on this in a project.

Upvotes: 0

RafaelTSCS
RafaelTSCS

Reputation: 1314

A good approach would be using a Factory/Service. take a look at this: Share data between AngularJS controllers

Upvotes: 1

Related Questions