2

Here's my setup, I have a backend API running on Tomcat and built in Spring and the frontend in Angular JS, data is passed back and forth via JSON. All operations on the backend API were tested with the REST console and the Angular app as well. The app is a CRUD for Teams which are described by an id, a name and a team rating , for example :

[{"id":69,"name":"test","rating":5},{"id":70,"name":"test 2","rating":6}]

I noticed that my views aren't updated after I add a new team or delete a new team even though the POST or DELETE requests executed successfully and the changes are reflected in the database (MySQL).

I'm not sure if I need to manually invoke $scope.$apply or if I need to implement promises to make the app work.

app.js

var teamApp = angular.module('teamApp',[
    'ngRoute',
    'teamControllers',
    'teamServices'
]);

teamApp.config(['$httpProvider', function($httpProvider) {
    delete $httpProvider.defaults.headers.common["X-Requested-With"];
}]);

teamApp.config(['$routeProvider',
    function($routeProvider) {
        $routeProvider.
            when('/teams', {
                templateUrl: 'views/team-list.html',
                controller: 'teamController'
            }).
            when('/team/:teamId', {
                templateUrl: 'views/team-detail.html',
                controller: 'teamDetailController'
            }).
            when('/teams/create', {
                templateUrl: 'views/team-create.html',
                controller: 'teamCreateController'
            }).
            otherwise({
                redirectTo: '/teams'
            });
    }]);

controllers.js

var teamControllers = angular.module('teamControllers', []);

teamControllers.controller('teamController',
    ['$scope', 'Teams', 'Teams', '$location',
    function($scope, Teams, Team, $location) {

    $scope.viewTeam = function(teamId) {
        $location.path('/team/'+teamId);
    };

    $scope.createTeam = function () {
        $location.path('/teams/create');
    };

    $scope.teams = Teams.query();
    $scope.teams.$promise.then(function(result){
        console.log('Success ' + result);
        $scope.teams = result;
    });

}]);

teamControllers.controller('teamDetailController',
    ['$scope', '$routeParams', 'Team', '$location',
    function($scope, $routeParams, Team, $location){

    $scope.cancel = function() {
        $location.path('/teams');
    };

    $scope.deleteTeam = function(teamId) {
        Team.delete({teamId: teamId});
        $location.path('/teams');
    };

    $scope.team = Team.show({teamId: $routeParams.teamId});

}]);

teamControllers.controller('teamCreateController',
    ['$scope', 'Teams', '$location',
    function($scope, Teams, $location){

    $scope.createTeam = function() {
        Teams.create($scope.team);
        $location.path('/teams');
    }

    $scope.cancel = function() {
        $location.path('/teams');
    };

}]);

services.js

var teamServices = angular.module('teamServices', ['ngResource']);

teamServices.factory('Teams', ['$resource',
    function($resource){
        return $resource('http://localhost:8080/api/teams', {}, {
            query: {method:'GET', isArray:true},
            create: {method:'POST'}
        });
    }]);

teamServices.factory('Team', ['$resource',
    function($resource){
        return $resource('http://localhost:8080/api/team/:teamId', {}, {
            show : {
                method:'GET'
            },
            delete : {
                method:'DELETE'
            }
        });
    }]);

index.html

<html lang="en" ng-app="teamApp">

    <head>

        <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css" />
        <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
        <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css">

        <style>
            body {
                padding-top: 60px;
            }
            @media (max-width: 980px) {
                body {
                    padding-top: 0;
                }
            }
        </style>

        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
        <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
        <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular-route.min.js"></script>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular-resource.min.js"></script>

        <script src="js/app.js"></script>
        <script src="js/controllers.js"></script>
        <script src="js/services.js"></script>

    </head>

    <body>

        <div ng-view></div>

    </body>

</html>

Solution

In the controllers.js I've changed the createTeam and deleteTeam calls and used promises, for example:

Before:

    $scope.createTeam = function() {
        Teams.create($scope.team);
        $location.path('/teams');
    }

After:

$scope.createTeam = function() {
    Teams.create($scope.team).$promise.then(
        function(result){
            console.log('Success' + result);
            $location.path('/teams');
        },
        function(error){
            alert(error);
            console.log(error);
        }
    );
}
cristi _b
  • 1,783
  • 2
  • 28
  • 43
  • By looking really quick over your code, I think you don't refresh the data after an action, you have two options, either after you make a POST/DELETE call the server again to get the new data in the view, EITHER you also `visibly` delete the data from the `$scope` until the next call to the backend happens. – Arthur Kovacs Apr 05 '14 at 10:52
  • @ArthurKovacs I've looked over my network requests, the POST is executed , I'm redirected to the main page and a GET request isn't performed ... I'm not sure how to force the GET to be re-executed ... I thought the two-way-data-binding story would work ... – cristi _b Apr 05 '14 at 11:02

1 Answers1

3

Now I read a bit more carefully, hope I'm not wrong, see this about promises. I think that you are not waiting for the DELETE or POST request to complete, and you are going on the teams page where you make a GET query to list all the teams, You should redirect on the teams page on the success return of the POST/DELETE or you should chain your request so the GET runs AFTER the POST/DELETE, because, ATM, it appears that you are trying to make the second CALL before the first one is DONE.

You have a promise on the TEAMS QUERY, but you don't have one on the POST/DELETE, as far as I can tell.

I might be wrong though, check this out nonetheless.

Community
  • 1
  • 1
Arthur Kovacs
  • 1,710
  • 2
  • 17
  • 24
  • i've extended the service call in the controller by adding .$promise.then(...) calls and as expected , after the location is changed the GET call is executed and the view is reflecting the changes ... the question is updated with the answer – cristi _b Apr 05 '14 at 11:47
  • I have the same issue, but my view still doesn't get updated. I copied your implementation, but my 'index' view won't update. – Rob Angelier Jul 29 '14 at 08:50