scope and controller instantiation with ui router

可紊 提交于 2019-12-17 09:21:55

问题


I am confused about when controllers get instantiated. Also, how do controllers gets instantiated when nesting states. I might be confused how scope gets attached to view and controller, that is, if every view gets its own controller and scope or do they share the same scope.

Can someone please explain when controllers get instantiated? Under nested routes do all the views share one controller and scope? What happens when I switch states and go back to a state does another controller get instantiated?

Below are my routes(config file ):

.config (googleAnalyticsCordovaProvider, $stateProvider, $urlRouterProvider, IdleProvider, KeepaliveProvider) ->

   $stateProvider

  .state('app', {
    url: '/app',
    abstract: true,
    templateUrl: 'templates/menu.html',
    controller: 'AppController'
  })

  .state('app.pincode', {
    url: '/pincode',
    views: {
      menuContent: {
        templateUrl: 'templates/pincode-yield.html',
        controller: 'PincodeController'
      }
    }
  })

  .state('app.pincode.create', {
    url: '/create',
    views: {
      pincode: {
        templateUrl: 'templates/pincode-create.html',
        controller: 'PincodeController'
      }
    }
  })

  .state('app.pincode.pincodeLogin', {
    url: '/login',
    views: {
     pincode: {
        templateUrl: 'templates/pincode-login.html',
        controller: 'PincodeController'
      }
    }
  })

  .state('app.pincode.settings', {
    url: '/settings',
    views: {
      pincode: {
        templateUrl: 'templates/settings.html',
        controller: 'PincodeController'
      }
    }
  })

回答1:


To get even more detailed answers, we can/should observe the source code and check the documentation. Let me try to explain all three questions (and also cite from code and doc).

1. When do controllers get instantiated?

Here we can observe the code of the ui-view directive:

[$ViewDirective.$inject = \['$state', '$injector', '$uiViewScroll', '$interpolate'\];][1]

Controllers are related to views. Those views, which are defined inside of a .state() as the views object:

.state('...', {
  // The view definition
  views : {
    '' : {
      template: ...
      controller: ...
      resolve: ..
    }
  },
  resolve: ...
}

So, whenever is view (the ui-view) filled with settings defined inside of a state view, it acts almost as a standard, but enhanced directive.

1) Template is found,
2) Resolves are resolved
...
x) Controller is instantiated...

View targets (ui-view directives) could use names, and could be filled by different states in the hierarchy.

It could mean, that there could be a content inside of one view (e.g. title), defined by parent as well as replaced by child

// parent
.state('parent', {
  views : {
    '' : {...} // the main parent view, with ui-view="title"
    'title@parent' : { ...} // here we go and fill parent's ui-view="title"
  },
  ...
}

// child
.state('parent.child', {
  views : {
    'title' : { ...} // here we change the parent's target ui-view="title"
  },
  ...
}

The above state definition will (whenever we transition among these two states) do:

  • The $state.go('parent') - the view (template, controller...) defined in 'title@parent' : { ...} will be injected into target ui-view="title" and instantiated as described above

  • The $state.go('parent.child') - almost the same, just the view will be taken from child state/view defintion 'title' : { ...}. That will replace the content of the ui-view="title" and will be instantiated as described above

This will be happening every time we do go from parent to child and from child to parent.

2. Under nested routes do all the views share one controller and scope?

A simple answer is NO, there is no common sharing.

In fact, each controller has its own scope, the one which is created from parent view scope. Firstly the documentation:

What Do Child States Inherit From Parent States?

...

Scope Inheritance by View Hierarchy Only

Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).

It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.

So, whenever is our controller (well the view with template, controller...) injected into parent's target ui-view="..." it gets inherited scope:

newScope = scope.$new();

That in a nutshell means that JS objects (e.g. scope.Model = {}) can be shared among child and parent.

$scope.Model.id = 1; // will refer to the same id in both parent & child

However, basic Javascript types are not passed by reference, and so their values are not automatically synchronised between scopes:

// set in parent
$scope.id = 1;
// in child after inherted still === 1
$scope.id = 2; // now 2 for a child, different value in parent - still === 1

It's worth reading more about prototypical inheritance here:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

3. What happens when I switch states and go back to a state - does another controller get instantiated?

It depends.

If the parent sub view (remember ui-view="title" above) is replaced by child view, and then it is re-created (transitioning from child to parent) - such controller wil be re-initialized (discussed above).

But when we speak about the main parent view (usually unnamed), which represents the parent (For example the unnamed view below with controller 'ParentMainCtrl')

.state('parent', {
  views : {
    '' : {  //  // the main parent view
      controller: 'ParentMainCtrl',
    }
    'title@parent'
    'tooltip@parent'
  },

Then we can be sure that such controller is NOT re-instantiated. It lives during the lifetime of all its children, plus a parent's one (no child state selected).

To re-load this view/controller, we have to use an option reload

$state.go(to, params, options)

... options Options object. The options are:

  • ...
  • reload - {boolean=false}, If true will force transition even if the state or params have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd use this when you want to force a reload when everything is the same, including search params.

Hope that helps a bit. For further information, check out these resources:

  • Nested States & Nested Views
  • Multiple Named Views
  • API Reference
  • State.js of the sample application - I would say the best documented piece of code ever



回答2:


Controllers get instantiated whenever you visit the specific state. For example, while visiting app.pincode.pincodeLogin for the first time one AppController and two PincodeControllers are constructed, each with its own view assuming you got the templates right. Switching to 'app.pincode.settings' would destroy the innermost controller and replace it with a new one, althought the two controllers higher at the hierarchy will not be touched. Scopes follow the standard AngularJS' inheritance pattern, they are not isolated.

You probably would want to remove the controllers in the sub states (and handle the business logic in the parent controller) or have a distinct controller for each state - the same controller for different templates and views is usually a sign of bad design.




回答3:


Controllers get instantiated when the corresponding views are loaded for the first time.

For example if you have 3 tabs associated with 3 controllers - then the controller associated with the default view instantiates First. Next when you load the other views the associated controllers also get instantiated.

But interestingly, once a view is loaded in the DOM - it is cached by-default. When a view is navigated away from, its element is left in the DOM, and its scope is disconnected from the $watch cycle. When navigating to a view that is already cached, its scope is then reconnected, and the existing element that was left in the DOM becomes the active view.



来源:https://stackoverflow.com/questions/29107012/scope-and-controller-instantiation-with-ui-router

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!