germainelol
germainelol

Reputation: 3331

AngularJS - How to update data in the View using a Service?

I'll explain what I have so far. I have two controllers which are both using a movieService I have created which fetches a list of movies. The controllers are like this:

app.controller('MovieCtrl', ['$scope', 'movieService', function($scope, movieService) {

  $scope.movieService = movieService;

}]);

app.controller('NavCtrl', ['$scope', 'movieService', function($scope, movieService) {

  $scope.movieService = movieService;

}]);

My Service looks like this:

app.service('movieService', ['$http', function($http) {
        var movie = undefined;
        var relatedMovies = undefined;
        var searchTerm = undefined;

        this.update = function(search) {
            searchTerm = search;
            fetch();
        };

        function fetch() {
            $http.get(/* some http call that puts data into movie */);

            $http.get(/* some http call that puts data into relatedMovies */);
        };

}]);

And my related view code:

<input type="text" ng-model="searchTerm" ng-model-options="{debounce: 1500}" ng-change="movieService.update(searchTerm)">

<h1>{{ movieService.movie.Title }}</h1>

So on my view I have a search bar that when submitting the search term will use movieService.update(searchTerm), which is working fine because I can log the output from fetch() to console and it will show me the movie data.

Inside the movie variable there is a Title variable, so right now, I am using {{ movieService.movie.Title }} to try and display the title of the movie in the view. The problem is that the $scope.movieService data is not updated in real time, so if I run a new search within the service, the data in the view will not be updated unless I manually do it. When the data in movieService is updated, the view should be too.

So here comes my question, how would I make sure that these $scope.movieService variables in the controllers are always up-to-date with the service? Should I use $watch or something like that? What is the best way to achieve this?

Update: Added CodePen http://codepen.io/anon/pen/JdMxaZ

Upvotes: 1

Views: 3288

Answers (2)

skeggse
skeggse

Reputation: 6323

The problem is that your movie variable is just a variable in a service. Nothing about being a variable in a service grants the variable special powers. In order to see that variable in your controller, you need to make it part of the service itself. The service is just an object, and that's what you add your update function to. You need to make your movie and relatedMovies variables part of the service object.

Here's one way to solve this problem. The movieData object is just one way to solve this problem. Either way, you need to be changing the value of an object field as opposed to the value of a local variable.

app.service('movieService', function($http) {
    var movieData = {
        movie: undefined,
        relatedMovies: undefined
    };

    var searchTerm = undefined;

    movieData.update = function(search) {
        // searchTerm is fine because you're not trying to access it from the
        // controller
        searchTerm = search;
        fetch();
    };

    this.movieData = movieData;

    function fetch() {
        $http.get(/* movieData.movie = http data */);
        $http.get(/* movieData.relatedMovies = http data */);
    };
});


app.controller('MovieCtrl', [function($scope, movieService) {
  $scope.movieService = movieService.movieData;
});

app.controller('NavCtrl', function($scope, movieService) {
  $scope.movieService = movieService.movieData;
});

You can also set a variable to the value of this in the service function and change the value of movie and relatedMovies on that variable.

app.service('movieService', function($http) {
    var movieService = this;
    // modifying this modifies movieService and vice-versa
    this.movie = undefined;
    this.relatedMovies = undefined;

    var searchTerm = undefined;

    this.update = function(search) {
        // searchTerm is fine because you're not trying to access it from the
        // controller
        searchTerm = search;
        fetch();
    };

    function fetch() {
        $http.get(/* movieService.movie = http data */);
        $http.get(/* movieService.relatedMovies = http data */);
    };
});


app.controller('MovieCtrl', [function($scope, movieService) {
  $scope.movieService = movieService;
});

app.controller('NavCtrl', function($scope, movieService) {
  $scope.movieService = movieService;
});

Upvotes: 2

Pitipong Guntawong
Pitipong Guntawong

Reputation: 192

I usually store data in $rootScope so if you put the search result in $rootScope it will refresh real-time.

another method is to call the broadcast $rootScope.$broadcast(name, args) which is not really practical

Upvotes: -1

Related Questions