Используйте angular -ui-router с bootstrap $modal для создания многоэтапного мастера
FAQ для ui-router содержит раздел об интеграции с модальностями bootstrap $, но он ничего не говорит о абстрактных представлениях. У меня есть 3 представления под одним абстрактным видом, поэтому примерно следующее.
$stateProvider
.state('setup', {
url: '/setup',
templateUrl: 'initialSetup.html',
controller: 'InitialSetupCtrl',
'abstract': true
})
// markup for the static view is
<div class="wizard">
<div ui-view></div>
</div>
.state('setup.stepOne', {
url: '/stepOne',
controller: 'SetupStepOneCtrl',
onEnter: function($stateParams, $state, $modal) {
$modal.open{
backdrop: 'static',
templateUrl: 'setup.stepOne.html',
controller: 'SetupStepOneCtrl'
})
}
})
.state('setup.stepTwo', {
url: '/stepTwo',
controller: 'SetupStepTwoCtrl',
onEnter: function($stateParams, $state, $modal) {
$modal.open({
backdrop: 'static',
templateUrl: 'setup.stepTwo.html',
controller: 'SetupStepTwoCtrl'
})
}
})
.state('setup.stepThree', {
url: '/stepThree',
templateUrl: 'setup.stepThree.html',
controller: 'SetupStepThreeCtrl'
...
});
}]);
Я также попытался добавить блок onEnter в абстрактное состояние и удалить onEnter из каждого из трех дочерних состояний. На самом деле это кажется мне правильным. Абстрактное состояние инициализирует и открывает $modal, а последующие состояния должны интерполироваться, но когда я это пробовал, контейнер ui-view был пуст.
Я могу думать о некоторых других хакерских способах обхода этого, но думал, что попрошу посмотреть, есть ли канонический способ справиться с этим.
Ответы
Ответ 1
Альтернативный способ - использовать ng-switch
с комбинацией ng-include
внутри контроллера $modal
для динамической загрузки шаблонов шага мастера, то есть если вы не против совместного использования одного и того же контроллера для всех шагов мастера:
<div ng-switch="currentStep.number">
<div ng-switch-when="1">
<ng-include src="'wizardModalStep1.html'"></ng-include>
</div>
<div ng-switch-when="2">
<ng-include src="'wizardModalStep2.html'"></ng-include>
</div>
<div ng-switch-when="3">
<ng-include src="'wizardModalStep3.html'"></ng-include>
</div>
</div>
Вот Plunker с рабочим примером: http://plnkr.co/edit/Og2U2fZSc3VECtPdnhS1?p=preview
Надеюсь, что это поможет кому-то!
Ответ 2
Я использовал следующий подход для разработки мастера. это может помочь вам.
Я использовал состояния, подобные приведенному ниже, с свойством parent.
var home = {
name: 'home',
url: '/home',
controller: 'MainController',
templateUrl: '/html/main.html'
},
sampleWizard = {
name: 'sampleWizard',
url: '/sampleWizard',
controller: 'sampleWizardController',
templateUrl: '/html/sd/sample/sampleWizard.html'
},
sampleSectionOne = {
name: 'sampleSectionOne',
url: '/sampleSectionOne',
parent: sampleWizard,
controller: 'sampleSectionOneController',
templateUrl: '/html/sd/sample/sampleSectionOne.html'
},
sampleSectionTwo = {
name: 'sampleSectionTwo',
url: '/sampleSectionTwo',
parent: sampleWizard,
controller: 'sampleSectionTwoController',
templateUrl: '/html/sd/sample/sampleSectionTwo.html'
};
$stateProvider.state(home);
$stateProvider.state(sampleWizard);
$stateProvider.state(sampleSectionOne);
$stateProvider.state(sampleSectionTwo);
Ответ 3
Я не уверен, что вы хотите запускать модальный каждый раз, когда вы переходите к следующему шагу.
Я думаю, что все, что вам нужно сделать, это создать модальный вид(), тогда на каждом шаге есть модальный шаблон, назначенный ему.
каждый шаблон должен выглядеть так:
<div class="modal fade in" id="whatever" style="display:block">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<a ui-sref="next_page_route_id" type="button" class="btn btn-primary">Next</a>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="modal-backdrop fade in"></div>
На последнем экране вы можете добавить submit-reject = "modal" в submit, и вы закончили
Ответ 4
Я имел дело с похожим сценарием, где мне приходилось создавать мастер (который позволяет вам пройти шаги и, наконец, нажать на сводку и сохранить).
Для этого я создал разные представления, но с одним контроллером.
Поскольку размер контроллера уменьшается после каждой повторной маршрутизации, мне пришлось сохранить область действия контроллера (в основном объект модели, связанного с мастером) в объекте службы для каждой маршрутизации в мастере (Captured through location.path()) и загрузить эту объект обратно из служебного объекта при загрузке контроллера. Что-то вроде ниже: -
// Saving data on routing
$scope.nextPage = function () {
service.ModelForWizard = $scope.ModelForWizard;
switch ($location.path()) {
case RouteOfPage1:
//Do some stuff
break;
case RouteOfPage2:
//Do some stuff
break;
default:
}
Сервис или factory сохраняется на протяжении всего срока службы пользовательского сеанса и идеально подходит для хранения пользовательских данных.
Еще одна полезная вещь - использование "Разрешить" на маршрутах.
Это гарантирует, что следующая страница не отображается, пока требуемые данные (обычно данные поиска) не будут загружены. Код разрешения - это примерно так:
.when('/RouteForWizardPage1', {
templateUrl: '/templates/ViewPage1Wizard.html',
caseInsensitiveMatch: true,
controller: 'wizardController',
resolve: {
wizardLookupDataPage1: function (Service) {
return service.getwizardModelLookupDataPage1().$promise;
}
},
})
Ответ 5
Я работал в одном и том же. Что сработало для меня, это опорожнение свойства url первого под-состояния. Следовательно, для первого дополнительного состояния ваш код должен выглядеть следующим образом:
.state('setup.stepOne', {
url: '',
controller: 'SetupStepOneCtrl',
onEnter: function($stateParams, $state, $modal) {
$modal.open{
backdrop: 'static',
templateUrl: 'setup.stepOne.html',
controller: 'SetupStepOneCtrl'
})
}
})
Кроме того, если вы не используете свойство url для вызова других 3-х под-состояний и вызываете их только с использованием имени состояния, вам необязательно упоминать свойство URL-адреса для них.
Ответ 6
Если вы хотите показать мастер в модальном диалоговом окне и иметь отдельное состояние для каждого из шагов мастера, вам нужно иметь в виду, что модальный диалог отображается полностью вне вашей иерархии представлений. Поэтому вы не можете ожидать какого-либо взаимодействия между механизмами рендеринга ui-router
и содержимым диалогового окна.
Надежное решение состоит в том, чтобы поместить логику управления содержимым мастера в область родительского состояния
$scope.wizard = {
scope: $scope.$new(),
show: function (template) {
// open the $modal if not open yet
// purge scope using angular.copy()
// return $scope.wizard.scope
},
// private
open: function () {
$modal.open({
scope: $scope.wizard.scope,
// ...
});
}
};
а затем вручную отобразить соответствующий контент из каждого из под-состояний и при необходимости манипулировать областью мастера
$scope.wizard.show('someTemplate');
$scope.wizard.scope.user = ...;
Когда мы столкнулись с этой проблемой в нашем проекте, мы решили после некоторого обсуждения, что нам действительно не нужны отдельные состояния ui-router
для шагов мастера. Это позволило нам создать директиву wizard
, используемую внутри шаблона диалога, чтобы прочитать конфигурацию мастера из области действия (используя формат, аналогичный определению состояния ui-router
), предоставить методы для продвижения мастера и визуализировать соответствующий вид/контроллер внутри диалогового окна.
Ответ 7
Чтобы создать многошаговые мастера, вы можете использовать этот модуль (я автор): https://github.com/troch/angular-multi-step-form.
Он позволяет создавать шаги, подобные представлениям, и вы можете включить навигацию (кнопка назад/вперед, URL-адрес с параметром поиска URL). Примеры здесь.