Направлення користувача на дочірній стан, коли він переходить у його батьківський стан за допомогою UI-Router


77

Розглянемо наступне:

.state('manager.staffList', {url:'^/staff?alpha', templateUrl: 'views/staff.list.html', data:{activeMenu: 'staff'}, controller: 'staffListCtrl'})
.state('manager.staffDetail', {url:'^/staff/{id}' , templateUrl: 'views/staff.html', data:{activeMenu: 'staff'}, controller: 'staffDetailsCtrl'})
  .state('manager.staffDetail.view', {url:'/view',  templateUrl: 'views/staff.details.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.schedule', {url:'/schedule', templateUrl:'views/staff.view.schedule.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.history', {url:'/history' , templateUrl:'views/staff.view.history.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.log', {url:'/log', templateUrl:'views/staff.view.log.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.files', {url:'/files', templateUrl:'views/staff.view.files.html', data:{activeMenu: 'staff'}})
  .state('manager.staffDetail.edit', {url:'/edit',  templateUrl: 'views/staff.edit.html', data:{activeMenu: 'staff'}})

Якщо я перейду до domain.com/staff/1234/view, як мені встановити за замовчуванням manager.staffDetail.view.scheduleдочірній стан?


FYI, наразі я використовую redirectToметод, знайдений тут stackoverflow.com/questions/29491079/…
Meeker

Будь ласка, НЕ редагуйте це для створення більш вертикального коду. Код відформатований спеціально для візуального відображення стану дитини у порівнянні з батьками.
Мікер

@UdayHiwarale - це те саме посилання, яке вже розміщено вище
Мікер

Моє ліжко. Я не бачив.
Удай Хіварале

Відповіді:


136
  1. Спочатку додайте властивість до 'manager.staffDetail.view'стану abstract:true. Це не потрібно, але ви хочете встановити це, оскільки ви ніколи не переходили б до цього стану безпосередньо, ви завжди б переходили до одного з його дочірніх станів.

  2. Потім виконайте одне з наступного:

    • Дайте 'manager.staffDetail.view.schedule'штату порожню URL-адресу . Це змусить його збігатися з тією самою URL-адресою, що і URL-адреса батьківського стану, оскільки вона нічого не додає до батьківської URL-адреси.

      .state('manager.staffDetail.view.schedule', {url:'', ...

    • Або якщо ви хочете залишити URL-адресу дочірнього маршруту за замовчуванням незмінним, налаштуйте переспрямування у своєму module.config. Цей код тут перенаправить будь-яке місце розташування '/staff/{id}/view'на місце розташування '/staff/{id}/view/schedule':

      $urlRouterProvider.when('/staff/{id}/view', '/staff/{id}/view/schedule');


4
Для $urlRouterProviderперенаправлення я отримав помилку при використанні посилання з ui-sref="manager.staffDetail.view", тому мені потрібно було видалити abstract: trueз декларації батьківського стану.
colllin

4
другий варіант не буде працювати для внутрішніх посилань ui-sref (він не буде переходити до підстанції)
Степан Суворов

20

Щоб встановити дочірній вигляд за замовчуванням, перегляньте цей приклад . При натисканні Route 1завантажити стан за замовчуваннямroute1.list

// For any unmatched url, send to /route1
$stateProvider
  .state('route1', {
      url: "/route1",
      abstract:true ,
      templateUrl: "route1.html"
  })
  .state('route1.list', {
      url: '',
      templateUrl: "route1.list.html",
      controller: function($scope){
        $scope.items = ["A", "List", "Of", "Items"];
      }
  })
  .state('route1.desc', {
      url: "/desc",
      templateUrl: "route1.desc.html",
      controller: function($scope){
        $scope.items = [];
      }
  })
  .state('route2', {
    url: "/route2",
    templateUrl: "route2.html"
  })
  .state('route2.list', {
    url: "/list",
    templateUrl: "route2.list.html",
    controller: function($scope){
      $scope.things = ["A", "Set", "Of", "Things"];
    }
  })

Якщо у route1.descвас немає URL-адреси, ви все одно можете отримати його за допомогою $state.go, але route1.listза замовчуванням буде завантажено /route1:) це корисно, якщо ви не хочете надавати прямий доступ до стану через url
Андрій Коджея,

2
з цим є велика проблема, якщо ми хочемо використовувати батьківський стан в ui-sref
Kishore Relangi

вам потрібно скористатися href = "/ abstractroute" для посилання на батьків
Ерік Шелл

Хто-небудь може пояснити мені, чому route1державі в цьому прикладі потрібен templateUrl? Або більш загально, навіщо abstract:trueдержаві потрібен шаблон?
грант

у батька дитини повинен бути той, з abstract:true
ким

8

Я зіткнувся з тим самим питанням і знайшов таке рішення:

https://github.com/angular-ui/ui-router/issues/948#issuecomment-75342784

Це цитується з @christopherthielen на github

"Наразі не оголошуйте свій штат абстрактним і використовуйте цей рецепт:"

 app.run($rootScope, $state) {
    $rootScope.$on('$stateChangeStart', function(evt, to, params) {
      if (to.redirectTo) {
        evt.preventDefault();
        $state.go(to.redirectTo, params)
      }
    });
  }

  $stateProvider.state('parent' , {
      url: "/parent",
      templateUrl: "parent.html",
      redirectTo: 'parent.child'
  });

  $stateProvider.state('parent.child' , {
      url: "/child",
      templateUrl: "child.html"
  });

Ось розбивка того, як працює процес:

  1. Користувач переходить до стану “батьківський”
  2. Подія “$ stateChangeStart” запускається
  3. Слухач для “$ stateChangeStart” ловить подію і передає “toState” (який є “батьківським”) та “event” у функцію обробника
  4. Функція обробника перевіряє, чи встановлено “redirectTo” на “toState”.
  5. Якщо “redirectTo” НЕ встановлено, нічого не відбувається, і користувач переходить у стан “toState”.
  6. Якщо встановлено значення “redirectTo”, подія скасовується (event.preventDefault), а $ state.go (toState.redirectTo) відправляє їх до стану, зазначеного в “redirectTo” (тобто “parent.child”).
  7. Подія “$ stateChangeStart” запускається знову, але цього разу “toState” == “parent.child” і параметр “redirectTo” не встановлений, тому вона продовжує “toState”.

хто-небудь може це пояснити. Чи це не стане нескінченною петлею?
Kishore Relangi

Привіт Кішоре! Я оновив відповідь, щоб пояснити, як це працює. НЕ буде нескінченного циклу, якщо ви явно не вказали "батьківський" стан в опції "redirectTo".
Чак Д,

Я спробував це, але, на жаль, це не працює для мене. Я використовую ui-router v0.3.1
Hussain

7

Досить пізно, але я думаю, що ви можете "перенаправити" в стан, який хочете.

.state('manager.staffDetail.view', {
    url:'/view',
    templateUrl: 'views/staff.details.html',
    controller: 'YourController'
})

app.controller('YourController', ['$state',
function($state) {
    $state.go('manager.staffDetail.view.schedule');
}]);

Ви можете коротко написати вам контролер прямо в конфігу штату.


3
Я спробував це, але це подвоїть контролери завантаження, вирішення та все, що є onStateChange. Я закінчив, просто використовуючи $ urlRouterProvider.when ('/ app / service', '/ app / service / list')
Meeker

буде це навантаження лише двічі або нескінченно, оскільки дочірній стан також знову викликає батьківський стан, оскільки там ми знову переспрямовуємо до дочірнього.
Kishore Relangi

Якщо у вашій навігації є батьківський sref, він не буде працювати при наступних клацаннях - лише при початковому завантаженні контролера.
Джонатан Хілл

3

Я змінив 'manager.staffDetial.view' на абстрактний стан і залишив порожню адресу мого дочірнього стану за замовчуванням ''

// Staff
.state('manager.staffList',    {url:'^/staff?alpha',      templateUrl: 'views/staff.list.html', data:{activeMenu: 'staff'}, controller: 'staffListCtrl'})
.state('manager.staffDetail',   {url:'^/staff/{id}', templateUrl: 'views/staff.html', data:{activeMenu: 'staff'}, controller: 'staffDetailsCtrl'})
.state('manager.staffDetail.view',   {url:'/view', abstract: true, templateUrl: 'views/staff.details.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.schedule', {url:'', templateUrl:'views/staff.view.schedule.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.history', {url:'/history', templateUrl:'views/staff.view.history.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.log', {url:'/log', templateUrl:'views/staff.view.log.html', data:{activeMenu: 'staff'}})
    .state('manager.staffDetail.view.files', {url:'/files', templateUrl:'views/staff.view.files.html', data:{activeMenu: 'staff'}})
.state('manager.staffDetail.edit',   {url:'/edit',  templateUrl: 'views/staff.edit.html', data:{activeMenu: 'staff'}})

13
Отже, ви в основному зробили саме те, що я запропонував ... чому б тоді не дати моїй відповіді правильну позначку? Тож я можу отримати очки реп.
Тім Кіндберг

Я не впевнений, що ви знаєте, що означає слово "точно". Однак у вашому прикладі коду використано метод routeProvider. Я вирішив взагалі не використовувати це, а натомість тримати рішення всередині державного менеджера. Таким чином, код залишається чистим і не додає зайвих зайвих рядків коду. Ваш приклад - можлива відповідь, але не найбільш прийнятна відповідь.
Мікер

Здавалося, все, що ви робили, я вже згадував (хоча, так, код у моєму прикладі був непотрібним). Я: "... ви повинні встановити його в абстрактний стан". ВИ: "Я змінив" manager.staffDetial.view "на абстрактний стан ..." МЕНЕ: "Або інший варіант - дати графіку порожню URL-адресу." ВИ: "... і залишив порожнім URL-адресу мого дочірнього стану за замовчуванням". Серйозно не відчуваю жодних важких почуттів, я рада, що ви це зрозуміли.
Тім Кіндберг,

1
Вибачте, ваша відповідь заплутала, і не суть. Прочитавши ваше пояснення, я бачу, що ви дали окремі варіанти, і врешті-решт, якби я якось поєднав ваш перший і останній варіант і залишив середню пропозицію, я мав би рішення. Мабуть, я бачу, куди ти йдеш, але я не впевнений, що це допомогло б наступному читачеві, якби я позначив твого як відповідь. Якщо ви хочете відредагувати свою відповідь і прояснити свою відповідь, я з радістю дам вам відповідь.
Мікер

Так, ти маєш рацію, я написав відповідь зі свого телефону ...: PI прибрав відповідь, сподіваюся, зараз це має більше сенсу. Також я помітив , що якщо я шукаю UI-маршрутизатор Google цей потік є четвертим результатом, так що це важливо , що у нас це дуже ясно.
Тім Кіндберг

1

У "angular-ui-router": "0.2.13", я не думаю, що рішення перенаправлення @ nfiniteloop буде працювати. Це спрацювало, коли я повернувся до 0.2.12 (і, можливо, довелося б розмістити $ urlRouterProvider.when перед дзвінком перед $ stateProvider?)

див. https://stackoverflow.com/a/26285671/1098564

та https://stackoverflow.com/a/27131114/1098564 для обхідного шляху (якщо ви не хочете повертатися до 0.2.12)

станом на 28 листопада 2014 р. https://github.com/angular-ui/ui-router/issues/1584 вказує на те, що він повинен запрацювати знову в 0.2.14


1

Це пізно, але всі відповіді тут не стосуються останньої версії angular-ui-router для AngularJS. Станом на цю версію (зокрема @ uirouter / angularjs # v1.0.x, ви можете просто ввести redirectTo: 'childStateName'другий параметр $stateProvider.state(). Наприклад:

$stateProvider
.state('parent', {
  resolve: {...},
  redirectTo: 'parent.defaultChild'
})
.state('parent.defaultChild', {...})

Ось відповідний розділ документації: https://ui-router.github.io/guide/ng1/migrate-to-1_0#state-hook-redirectto

Сподіваємось, це комусь допомагає!


0

ось дуже проста і прозора альтернатива, просто змінивши батьківський стан в маршрутизаторі інтерфейсу користувача:

  .state('parent_state', {
    url: '/something/:param1/:param2',
    templateUrl: 'partials/something/parent_view.html',  // <- important
    controller: function($state, $stateParams){
      var params = angular.copy($state.params);
      if (params['param3'] === undefined) {
        params['param3'] = 'default_param3';
      }
      $state.go('parent_state.child', params) 
    }
  })

  .state('parent_state.child', {
    url: '/something/:param1/:param2/:param3',
    templateUrl: '....',  
    controller: '....'
  })

0

Додайте angular-ui-router-default та додайте параметри abstractта defaultдо батьківського стану:

...

.state('manager.staffDetail.view', {abstract: true, default: '.schedule', url:'/view',  templateUrl: 'views/staff.details.html', data:{activeMenu: 'staff'}})
  .state('manager.staffDetail.view.schedule', {url:'/schedule', templateUrl:'views/staff.view.schedule.html', data:{activeMenu: 'staff'}})

...

Примітка: щоб це працювало, батьківський шаблон повинен бути <ui-view/>десь у ньому.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.