CLDev
CLDev

Reputation: 1567

UI-Router - scope not destroyed on state change?

I'm a new user to AngularJS and ui-router, and I'm trying to turn my head around on how the scope is managed. I was expecting the scope of an active controller would be destroyed when it becomes inactive on state change, however, it doesn't appear to be the case.

I've modified the example from UI-Router's website to illustrate the situation (see plunker below). Every time when the state route1.list/route2.list is triggered, they will emit an event on $rootScope. On receiving the event, a debug statement will be printed to console.

By toggling between the two states a few times, it is observed that all the controllers initialized previously responded the the event. So it appears that the scopes created by them have never been destroyed. Is this behavior expected? If so, what should I do such that only active controllers will respond to an event?

Plunker

Debug message printed on Console: enter image description here

Code:

var myapp = angular.module('myapp', ["ui.router"])
myapp.config(function($stateProvider, $urlRouterProvider){

// For any unmatched url, send to /route1
$urlRouterProvider.otherwise("/route1")

here is the route1

$stateProvider
  .state('route1', {
      url: "/route1",
      templateUrl: "route1.html"
  })
    .state('route1.list', {
        url: "/list",
        templateUrl: "route1.list.html",
        controller: function($rootScope, $scope){
          $rootScope.$emit("eventCT1");
          $rootScope.$on("eventCT2", fn);
          function fn () {
            console.log("Controller 1 receives an event emitted by Controller 2");
          }
          $scope.items = ["A", "List", "Of", "Items"];
        }
    })

and here is route 2

  .state('route2', {
      url: "/route2",
      templateUrl: "route2.html"
  })
    .state('route2.list', {
        url: "/list",
        templateUrl: "route2.list.html",
        controller: function($rootScope, $scope){
          $rootScope.$emit("eventCT2");
          $rootScope.$on("eventCT1", fn);
          function fn () {
            console.log("Controller 2 receives an event emitted by Controller 1");
          }
          $scope.things = ["A", "Set", "Of", "Things"];
        }
    })
 ...

Upvotes: 9

Views: 8363

Answers (2)

Lakmal Caldera
Lakmal Caldera

Reputation: 1031

If you are using Ionic with Angular, you could use the life cycle events like so:

$scope.$on("$ionicView.beforeEnter", function(){
   //Do something every time this controller is the active scope.
})

You could play around with the other events provided in the above link as well. And it's probably best practise to minimize the use of $emit, which will lead to more predictable code and fewer state mutations.

Upvotes: -1

Radim Köhler
Radim Köhler

Reputation: 123861

If we want to do something with

1) $rootScope inside of the controller (which has very limited lifetime),

2) we must destroy that, when controller (its $scope in fact) is being destroyed

So, this is the way how to hook and unhook

// get remove function
var removeMe = $rootScope.$on("eventCT2", ...);

// call that function
$scope.$on("$destroy", removeMe)

But, in the case above, we should not even try to

1) create some controller action for one state...

2) and expect it will be called in another controller from different state

These will never live together

Upvotes: 5

Related Questions