1

I am learning how to use resolve from an example, and applying it on to my Todo script.

Then I realised an issue, that the example is only showing me how to resolve GET call to get me the Todo List when I first visit this route.

However, in the same route same page I have an Add button to POST new todo item, also a Clear button to DELETE completed items.

Looking at my $scope.addTodo = function() { and $scope.clearCompleted = function () { I want to Resolve my TodoList again after the action. How can I do that?

Here is my code. In my code, the initial resolve: { todos: TodosListResl } is working, it hits TodosListResl function and produces the promise. However, I don't know what to do with addTodo and clearComplete when I want to resolve the todo list again.

enter image description here

main.js

var todoApp = angular.module('TodoApp', ['ngResource', 'ui']);
todoApp.value('restTodo', 'api/1/todo/:id');

todoApp.config(function ($locationProvider, $routeProvider) {
    $routeProvider.when("/", { templateUrl: "Templates/_TodosList.html", 
        controller: TodosListCtrl, resolve: { todos: TodosListResl } });
    $routeProvider.otherwise({ redirectTo: '/' });
});

//copied from example, works great
function TodoCtrl($scope, $rootScope, $location) {
    $scope.alertMessage = "Welcome";
    $scope.alertClass = "alert-info hide";

    $rootScope.$on("$routeChangeStart", function (event, next, current) {
        $scope.alertMessage = "Loading...";
        $scope.alertClass = "progress-striped active progress-warning alert-info";
    });
    $rootScope.$on("$routeChangeSuccess", function (event, current, previous) {
        $scope.alertMessage = "OK";
        $scope.alertClass = "progress-success alert-success hide";

        $scope.newLocation = $location.path();
    });
    $rootScope.$on("$routeChangeError", 
        function (event, current, previous, rejection) {
        alert("ROUTE CHANGE ERROR: " + rejection);
        $scope.alertMessage = "Failed";
        $scope.alertClass = "progress-danger alert-error";
    });
}
//also copied from example, works great.
function TodosListResl($q, $route, $timeout, $resource, restTodo) {
    var deferred = $q.defer();
    var successCb = function(resp) {
        if(resp.responseStatus.errorCode) {
            deferred.reject(resp.responseStatus.message);
        } else {
            deferred.resolve(resp);
        }
    };
    $resource(restTodo).get({}, successCb);
    return deferred.promise;
}
//now, problem is here in addTodo and clearCompleted functions, 
//how do I call resolve to refresh my Todo List again? 
function TodosListCtrl($scope, $resource, restTodo, todos) {
    $scope.src = $resource(restTodo);
    $scope.todos = todos;
    $scope.totalTodos = ($scope.todos.result) ? $scope.todos.result.length : 0;

    $scope.addTodo = function() {
        $scope.src.save({ order: $scope.neworder, 
                          content: $scope.newcontent, 
                          done: false }); 
                        //successful callback, but how do I 'resolve' it?
    };
    $scope.clearCompleted = function () {
        var arr = [];
        _.each($scope.todos.result, function(todo) {
            if(todo.done) arr.push(todo.id);
        });
        if (arr.length > 0) $scope.src.delete({ ids: arr }); 
        //successful callback, but how do I 'resolve' it?
    };   
}
Tom
  • 15,781
  • 14
  • 69
  • 111

1 Answers1

3

I think you're missing the point of resolve. The point of resolve is to " delay route change until data is loaded. In your case, you are already on a route, and you want to stay on that route. But, you want to update the todos variable on the successful callback. In this case, you don't want to use resolve. Instead, just do what needs to be done. For example

$scope.addTodo = function() {
    $scope.src.save({ order: $scope.neworder, 
                      content: $scope.newcontent, 
                      done: false }, function () {
        todos.push({ order: $scope.neworder, 
                      content: $scope.newcontent, 
                      done: false });
    }); 
                    //successful callback, but how do I 'resolve' it?
};

As a side point, I noticed you're using _ most likely from the Underscore library. You don't need to use another library for that because Angular already has $angular.forEach().

Community
  • 1
  • 1
Max
  • 8,671
  • 4
  • 33
  • 46
  • Thank you for reading my long question and giving me the precious opinion. So, does that mean, the Deferred Promise in my TodosListResl function is no use? What is the difference if I just do a direct $resource.get(); instead of having the trouble to construct a deferred promise. Since Resolve is already doing the delay? That is where I am confused, what is the point of the example to use resolve and promise together? – Tom Nov 15 '12 at 00:21
  • With only one route, you probably don't need resolve/deferred promises. Paraphrasing $resource docs: Calling a $resource method (like get()) immediately returns an empty reference (object or array). Once the server returns the data, that reference gets populated with the data. This is commonly used to assign a resource to a model: the empty object results in no rendering, then, once the data arrives, the model/object is populated with the data and the view automatically updates. So in most cases, you don't have to write callback functions for the action methods. – Mark Rajcok Nov 20 '12 at 03:21
  • Resolve and promises are useful if you want to delay showing a completely new view (say with ng-view) until the data (successfully) arrives from the server. Normally, you would be working with multiple routes with this. If you do need to work with a promise, I suggest looking at this answer, which uses $http instead of $resource: http://stackoverflow.com/a/12360882/215945 – Mark Rajcok Nov 20 '12 at 03:24
  • @MarkRajcok I have more than one route. Just cut everything else and make my code as short as possible. Example, you hit edit of an item, it goes to another route. But yeah, thanks for your reply. I will take a look. – Tom Nov 23 '12 at 02:35