2

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.

Yacub Ali
  • 137
  • 2
  • 11

3 Answers3

1

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

RafaelTSCS
  • 1,234
  • 2
  • 15
  • 36
1

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.

Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84
  • Hi Aluan, thanks for the detailed reply. However, the md-autocomplete seems to be blank but I can select the values from the blank dropdown list, so its definitely being populated. Also, the scope.selectedItemChange() is not being called whatsoever. Quite new to AngularJS, still learning something new everyday. – Yacub Ali Jul 20 '17 at 20:17
0

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.

SDSMTKyzer
  • 112
  • 10
  • 2
    Don't use `$rootScope` events for this kind of thing. Using a service/factory is easy and infinitely more maintainable. – Aluan Haddad Jul 19 '17 at 20:55
  • OK I'll check into them. Again, very new to AngularJS and that's just what a coworker suggested to me for our project. – SDSMTKyzer Jul 19 '17 at 20:56
  • 1
    I'll remove the downvote, since you are just starting out, but your coworker is emphatically wrong. – Aluan Haddad Jul 19 '17 at 20:59