Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ion-list does not refresh after $state.go is called

I am learning AngularJS and ionic framework using this tutorial:

http://www.htmlxprs.com/post/12/tutorial-on-using-parse-rest-api-and-ionic-framework-together

Everything works well up until the point when I create a new item in the createTodo state and then call $state.go('todos') to go back to my items list, here is the code for the create Todo Controller:

.controller('TodoCreateController', ['$scope', 'Todo', '$state', function($scope, Todo, $state) {
    $scope.todo = {};

    $scope.create = function() {
        Todo.create({content: $scope.todo.content}).success(function(data) {
            $state.go('todos', {}, {reload: true});
        });
    }
}])

Here is the code for the item list controller:

.controller('TodoListController', ['$scope', 'Todo', '$state', function($scope, Todo) {
    Todo.getAll().success(function(data) {
        $scope.items = data.results;
    });

    $scope.deleteItem = function(item) {
        Todo.delete(item.objectId);
        $scope.items.splice($scope.items.indexOf(item), 1);
    };
}])

Here are the states configured

.config(function($stateProvider) {
    $stateProvider.state('todos', {
        url: '/todos',
        controller: 'TodoListController',
        templateUrl: 'views/todos.html'
    }).state('createTodo', {
        url: '/todo/new',
        controller: 'TodoCreateController',
        templateUrl: 'views/create-todo.html'
    });
})

When the application starts, the method of the TodoListController is invoked thanks to the last line added and the end of the .run method in the main app.js (or at least thats my understanding):

.run(function($ionicPlatform, $state) {
    $ionicPlatform.ready(function() {

        if(window.cordova && window.cordova.plugins.Keyboard) {
            cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
        }
        if(window.StatusBar) {
            StatusBar.styleDefault();
        }
    });

    $state.go('todos');
})

My problem is that, as soon as the new item is created and I invoke $state.go('todos') from the TodoCreateController, it takes me back to the item list but the new item is not there and the method of the TodoListController is never invoked, therefore leaving the list outdated.

How can I refresh the list in the 'todos' state after a new item has been created?

like image 346
Arturo Rojas Avatar asked Jan 09 '15 03:01

Arturo Rojas


2 Answers

I found a rather elegant solution:

Inside my TodoListController I define an event listener like this:

$rootScope.$on('todo:listChanged', function() {
    $scope.updateList();
});

then comes the updateList() method

$scope.updateList = function() {
    Todo.getAll().success(function(data) {
        $scope.items = data.results;
    });
};

And finally in the TodoCreateController I $emit the event upwards as soon as the item is created and right before changing state

$scope.create = function() {
    Todo.create({content: $scope.todo.content}).success(function(data) {
        $scope.$emit('todo:listChanged');
        $state.go('todos');
    });
};

And voila! The list updates accordingly and I can now use the same event if I delete or update a list item

like image 53
Arturo Rojas Avatar answered Sep 17 '22 16:09

Arturo Rojas


I've encountered this and similar problems and it turned out that ionic view caching often was the reason for not calling the controller code when returning to a cached view.

Possible Solution

When separating controller code into one-time-initialization and code running when view is entered, you typically end with controllers looking like this:

// one-time initialization
$scope.updateList = function() {
    Todo.getAll().success(function(data) {
        $scope.items = data.results;
    });
};

$scope.$on('$ionicView.beforeEnter', function () {
    $scope.updateList();
});

This should solve your problem without having to trigger events or adding params or data to the route.

Alternative

It is possible to disable view caching in different ways:

  • add cache: false to the state definition
  • add cache-view="false" to the html <ion-view ...>
  • disable caching with $ionicConfigProvider.views.maxCache(0); (wouldn't recommend this)

Pitfall when using Sub-States

Not in your case, but if editing/creating rows in Sub-States (e.g. states todo for the list and todo.create for creating a new todo), there is an additional problem coming from ui-router:

When navigating from todo.create to state todo, your super-state todo won't be "executed", because you're already in this state when coming from todo.create. This is a common problem and can be solved by one of the more complicated solutions provided in other answers to this post.

like image 24
hgoebl Avatar answered Sep 17 '22 16:09

hgoebl