Подтвердить что ты не робот

Ui router - вложенные представления с общим контроллером

У меня есть абстрактный родительский вид, предназначенный для совместного использования контроллера со своими вложенными представлениями.

.state('edit', {
    abstract: true,
    url: '/home/edit/:id',
    templateUrl: 'app/templates/editView.html',
    controller: 'editController'
})
.state('edit.details', {
    url: '/details',
    templateUrl: 'app/templates/editDetailsView.html'
})
.state('edit.info', {
    url: '/info',
    templateUrl: 'app/templates/editInfoView.html'
})

Маршрутизация работает как ожидалось.

Проблема заключается в том, что когда я обновляю переменную $scope из одного из вложенных представлений, это изменение не отражается в представлении. Когда я делаю то же самое с родительского представления, он отлично работает. Это не ситуация, для которой требуется $apply.

Я предполагаю, что для каждого представления создается новый экземпляр editController, но я не уверен, почему и как его исправить.

4b9b3361

Ответ 1

Проблема здесь будет связана с этими Q и A: Как мне разделить данные области $между состояниями в angularjs ui-router?.

Способ решения проблемы скрыт в:

Понимание областей

В AngularJS дочерняя область, обычно прототипически наследуемая от родительской области.
 ...

Наличие символа '.' в ваших моделях будет гарантировать, что прототипное наследование находится в игре.

// So, use
<input type="text" ng-model="someObj.prop1"> 
// rather than
<input type="text" ng-model="prop1">.

А также этот

Наследование наследования по только иерархии представлений

Имейте в виду, что свойства области только наследуют цепочку состояний, если представления ваших состояний вложены. Наследование свойств области не имеет ничего общего с вложением ваших состояний и всего, что связано с вложением ваших представлений (шаблонов).

Вполне возможно, что у вас есть вложенные состояния, шаблоны которых заполняют u-views в разных не-вложенных местах на вашем сайте. В этом случае вы не можете ожидать доступа к переменным области представлений родительского состояния в представлениях дочерних состояний.

После этого мы должны сделать это в редакторе Controller

controller('editController', function ($scope) {
  $scope.Model = $scope.Model || {SomeProperty : "xxx"};
})

И мы можем даже повторно использовать это controller: 'editController' (мы не можем этого делать, потому что $scope.Model будет там - благодаря наследованию)

.state('edit', {
    abstract: true,
    url: '/home/edit/:id',
    templateUrl: 'app/templates/editView.html',
    controller: 'editController'
})
.state('edit.details', {
    url: '/details',
    templateUrl: 'app/templates/editDetailsView.html',
    controller: 'editController'
})
.state('edit.info', {
    url: '/info',
    templateUrl: 'app/templates/editInfoView.html',
    controller: 'editController'
})

Теперь тот же самый контроллер будет создаваться многократно (родительский все дети), но $scope.Model будет инициирован только один раз (внутри родителя) и доступен везде

Проверьте этот аналогичный рабочий пример здесь

Ответ 2

На основе комментария PilotBob

Можно ли это сделать при использовании шаблона controllerAs, дающего дочернему состоянию его собственный контроллер?

Я решил добавить другое решение, используя controllerAs, сохраняя выше/оригинальную концепцию

Существует рабочий плункер

В состояниях теперь будут разные контроллеры, а родительское состояние будет называть его "parentCtrl" (не будет перезаписано в дочерней области с помощью дочернего контроллера)

 .state("main", {
      controller:'mainController',
      controllerAs: "parentCtrl",
      ...
  .state("main.1", {
      parent: 'main',
      controller:'child1Controller',
      controllerAs: "ctrl",
      ...
  .state("main.2", {
      parent: 'main',
      controller:'child2Controller',
      controllerAs: "ctrl", 
      ... 

И это контроллеры:

.controller('mainController', function ($scope) {
    this.Model =  {Name : "yyy"};
})
.controller('child1Controller', function ($scope) {
    $scope.Model = $scope.parentCtrl.Model;
})
.controller('child2Controller', function ($scope) {
    $scope.Model = $scope.parentCtrl.Model; 
})

Проверьте его в действии здесь

Ответ 3

Другая альтернатива, использующая resolve

.state('edit', {
    abstract: true,
    url: '/home/edit/:id',
    templateUrl: 'app/templates/editView.html',
    controller: 'editController',
    resolve: {
        baseData: function() {
            return {};
        }
    }
})
.state('edit.details', {
    url: '/details',
    templateUrl: 'app/templates/editDetailsView.html',
    controller: 'editController'
})
.state('edit.info', {
    url: '/info',
    templateUrl: 'app/templates/editInfoView.html',
    controller: 'editController'
})


.controller('editController', function (baseData) {
    baseData.foo = baseData.foo || 'bar';
});