Какой минимум необходим для сохранения состояний angularjs ui-router с закрепленными состояниями от ui-router-extras?
У меня есть страница, которая включает элементы HTML-формы, распределенные по нескольким вкладкам. Я хочу, чтобы пользователь мог переключать вкладки без потери данных, которые он вводил в элементах формы (и я также хочу сохранить ненужные перезагрузки данных). И я все еще хочу иметь возможность передавать кому-то ссылку на конкретную вкладку.
Звучит так, будто липкие состояния пользовательского интерфейса должны делать именно то, что мне нужно. За исключением того, что мне не удалось заставить его работать.
Я изучил исходный код примера и, запустив пример, я, например, установил точку останова с помощью firebug в конструкторе контроллера инвентаризации, найденного в строке 57 в controllers.js, я вижу, что конструктор запускается только один раз. Мои конструкторы контроллеров, однако, запускаются снова и снова, и мое приложение ведет себя почти так же, как если бы залипающие состояния не существовали, хотя, если я включаю отладку залипающих состояний, это говорит мне, что оно что-то делает (деактивирующие и реактивирующие состояния).
Я нашел кого-то, кто заявил, что липкие состояния работают только с именованными представлениями в комментарии в этом ответе, поэтому я попытался дать своему представлению имя, но это не имело никакого значения.
Я попытался вставить явное "корневое состояние" перед моими вкладками.
Я попытался вставить контроллер с помощью ng-controller или по определению контроллера в состояниях.
Пример на github - это хорошая демонстрация, но она более чем минимальна и затрудняет понимание того, что действительно нужно, а что нет.
Каким будет минимальный пример того, что нужно, чтобы начать работать с липкими состояниями? (Бонус: что не так с моим кодом?).
Для справки вот планкр с моей неудачной попыткой (см. Историю, чтобы увидеть выбор предыдущей попытки).
Вот мой текущий ошибочный исходный код:
var log = '';
function mkController(msg) {
return function($scope) {
// This is the constructor of a controller
// I'd expect this constructor to the first time a state is loaded.
// When switching to a sister state and back it should not be called again.
if (!$scope.random) {
// I expect the $scope object to be retained when changing states for and
// back. So even if my assumption that the controller will be persistent
// would be wrong this is to check whether the $scope survives.
// If the scope survives the random number will be initialized only once
// and then it won't change anymore:
$scope.random = Math.round(Math.random()*10000);
}
// This log will tell us how often the controller constructor has been called
// (Should be only once, I think)
log += 'creating: ' + msg + '\n';
this.message = log;
}
}
angular.module('plunker', ['ui.router', 'ct.ui.router.extras.sticky', 'ct.ui.router.extras.dsr'])
.controller('ControllerA', mkController('ControllerA'))
.controller('ControllerB', mkController('ControllerB'))
.run(function($templateCache) {
$templateCache.put('root.html', '<div ui-view="myview"></div>');
$templateCache.put('templateA.html', '<div ng-controller="ControllerA as controller"><pre>Random: {{random}}, Message (templateA): {{controller.message}}</pre></div>');
$templateCache.put('templateB.html', '<div ng-controller="ControllerB as controller"><pre>Random: {{random}}, Message (templateB): {{controller.message}}</pre></div>');
})
.config(function($stateProvider) {
$stateProvider
.state('root', {
url: '/',
templateUrl: 'root.html'
}).state('root.stateA', {
url: '/stateA',
views: {
myview: {
templateUrl: 'templateA.html',
}
},
sticky: true,
deepStateRedirect: true
}).state('root.stateB', {
url: '/stateB',
views: {
myview: {
templateUrl: 'templateB.html',
}
},
sticky: true,
deepStateRedirect: true
});
})
.config(function($stickyStateProvider) {
$stickyStateProvider.enableDebug(true);
});
1 ответ
Я понял:
- Прежде всего, я не понимал, как на самом деле должны использоваться именованные представления: с отдельным представлением для каждой вкладки.
- Во-вторых, я не осознавал, что мне нужно скрывать и показывать взгляды самостоятельно.
Оба упомянуты на демонстрационной странице, но я должен признать, что я не очень внимательно прочитал текст демонстрационной страницы, так как думал, что это просто информация об этой конкретной демонстрации.
Во всяком случае: вот пример, который, я считаю, является минимумом, необходимым для того, чтобы заставить залипать состояния:
HTML
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link href="style.css" rel="stylesheet" />
<script data-semver="1.3.12" src="https://code.angularjs.org/1.3.12/angular.js" data-require="angular.js@1.3.x"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.js"></script>
<script src="ui-router-extras.js"></script>
<script src="app.js"></script>
</head>
<body>
<ul class="nav nav-tabs nav-tabs-head" role="tablist">
<li ui-sref-active="active"><a ui-sref="root.stateA" role="tab">StateA</a></li>
<li ui-sref-active="active"><a ui-sref="root.stateB" role="tab">StateB</a></li>
</ul>
<div ui-view="" />
</body>
</html>
JavaScript
var log = '';
function mkController(msg) {
return function($scope) {
// This is the constructor of a controller
// I'd expect this constructor to the first time a state is loaded.
// When switching to a sister state and back it should not be called again.
if (!$scope.random) {
// I expect the $scope object to be retained when changing states for and
// back. So even if my assumption that the controller will be persistent
// would be wrong this is to check whether the $scope survives.
// If the scope survives the random number will be initialized only once
// and then it won't change anymore:
$scope.random = Math.round(Math.random()*10000);
}
// This log will tell us how often the controller constructor has been called
// (Should be only once, I think)
log += 'creating: ' + msg + '\n';
this.message = 'Current msg: ' + msg + '\n\n' + log;
}
}
angular.module('plunker', ['ui.router', 'ct.ui.router.extras.sticky'])
.controller('ControllerA', mkController('ControllerA'))
.controller('ControllerB', mkController('ControllerB'))
.config(function($stateProvider) {
$stateProvider
.state('root', {
url: '/',
template: '<div ui-view="a" ng-show="$state.includes(\'root.stateA\')"></div><div ui-view="b" ng-show="$state.includes(\'root.stateB\')"></div>'
}).state('root.stateA', {
url: '/stateA',
views: {
'a@root': {
template: '<div ng-controller="ControllerA as controller"><h1>A</h1><pre>Random: {{random}}, Message (templateA): {{controller.message}}</pre></div>',
}
},
sticky: true
}).state('root.stateB', {
url: '/stateB',
views: {
'b@root': {
template: '<div ng-controller="ControllerB as controller"><h1>B</h1><pre>Random: {{random}}, Message (templateB): {{controller.message}}</pre></div>',
}
},
sticky: true
});
})
.config(function($stickyStateProvider) {
$stickyStateProvider.enableDebug(true);
})
.run(function ($rootScope, $state) {
$rootScope.$state = $state;
});