1

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

11
  • Where is your html view? The part that is actually showing the data? Commented Jun 30, 2015 at 3:59
  • I'll add that to the OP now @cerd Commented Jun 30, 2015 at 4:00
  • In what way do you need to manually update the data in the view for it to work? Commented Jun 30, 2015 at 4:01
  • Also it doesn't appear that your fetch function is actually returning the $http.get results - or that you have any other way of actually getting the data back to the controller. Commented Jun 30, 2015 at 4:02
  • Well you can see that the view is displaying the movie title, and the search bar is simply running update to update the movie data in the service. So in practical terms, if I run a new search in the search bar, I would like the movie title (and other information) to update in the view. If I search for "The Avengers", it would update the movie data in the service to this movie, and the controllers/view would in turn see that it has changed and update the view to show information about "The Avengers". Hope I was clear @skeggse Commented Jun 30, 2015 at 4:03

2 Answers 2

2

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;
});
Sign up to request clarification or add additional context in comments.

7 Comments

Awesome, thanks. So the trick is to make sure that this.movieData is holding the data so that the controllers can access it using movieService.movieData. Thanks again!
No problem. The trick is to have the data in an object (any object) that both contexts can access. $rootScope would have accomplished that goal, but doing so violates best-practices.
I think it is worth noting that this code could be much cleaner, I always refer people to John Papas angular style guide - it makes this problem non-existent github.com/johnpapa/…
@skeggse So it works just because it's inside an object using {}?
@cerd Yeah, that's what I was mentioning in the second paragraph when I said "You can also set a variable to the value of this in the service function and change the value of movie". @germainelol it works because it's in an object. The fact that I made an object using {} is of little consequence. I'll update my answer with an alternate example, but the bottom line is that in your fetch function you need to be changing the value of a field in an object, and not the value of a local variable.
|
-1

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

2 Comments

I'm not sure I want to use $rootScope, I'm trying to make sure that everything is done in an efficient, secure way. I'm trying not to start putting things in the $rootScope first.
This is not best practice, it violates the entire dogma of separating controller scopes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.