假设我有一个用于编辑eCard的Angular应用程序。创建新的eCard使用的路径类似于#/ecard/create
,而编辑现有eCard的使用路径诸如#/ecard/:id
。制表系统使我们可以一次打开多个电子贺卡以进行编辑。
我们想要一种自动保存功能,例如用户期望的功能。现代的Webmail或Wiki软件(或StackOverflow本身)。我们不希望在用户打开“创建”表单时保存电子贺卡草稿,因为这会给我们提供许多空白电子贺卡的草稿,因此一旦用户开始输入,我们便开始自动保存。
我想在我们的 Controller 中编写这样的代码(简化为不包括例如错误处理或在关闭选项卡时停止自动保存等):
$scope.autosave = function () {
ECardService.autosave($scope.eCard).then(function (response) {
$location.path('/ecard/' + response.id).replace();
$timeout($scope.autosave, AUTOSAVE_INTERVAL);
});
};
$timeout($scope.autosave, AUTOSAVE_INTERVAL);
上面的代码非常有用,除了以下几点:位置更改时,我们的 Controller 会重新加载, View 会重新渲染。因此,如果用户在自动保存完成时处于键入中间,则会出现短暂的闪烁,并且他们会失去位置。
我已经考虑了几种缓解此问题的方法:
1)更改路径以使用搜索路径,并在
reloadOnSearch
配置中将false
设置为ngRoute
。因此路径将从#/ecard?id=create
更改为例如#/ecard/id=123
,因此不强制重新加载。问题是我可能打开了多个电子贺卡,但我确实希望更改例如#/ecard/id=123
到#/ecard/id=321
触发路由更改并重新加载 Controller 。因此,这实际上是不可行的。2)在这种情况下,不要费心编辑URL并使用后退按钮,这会产生奇怪的行为。这很诱人,但是如果用户打开他们现有的电子贺卡列表并尝试打开已保存的特定电子贺卡,我们希望标签系统能够识别它应该仅显示当前现有的标签,而不是打开新的标签。
从理论上讲,我们可以通过更新标签系统使其更智能来解决此问题。不仅可以检查路径,还可以同时检查路径和持久性ID(我们可以将其存储在某个位置)。这将使制表系统变得更加复杂,并且对于此功能来说似乎有些过时了。
3)仅在用户未积极编辑时(例如,编写一个
$scope.userIsIdle()
函数,如果自用户进行任何修改以来至少10秒钟返回true
,则返回$location
,然后根据该更新路径。简化版本如下所示:$scope.updatePathWhenSafe = function (path) {
if ($scope.userIsIdle()) {
$location.path(path).replace();
} else {
$timeout(function () {
$scope.updatePathWhenSafe(path);
}, 1000);
}
};
我最终选择了选项3。它比选项#2简单得多,但是实现和测试却比我想要的要复杂得多,尤其是当我考虑到诸如“如果在此超时触发时选项卡不再是 Activity 选项卡?”之类的极端情况时,就更是如此。我希望选项4成为可能。
4)假定必要且可能,请在Angular外编辑当前位置和历史记录。这将是我的首选解决方案,但是我的研究表明,尝试绕过ojit_code服务来更改路径或编辑历史记录是不安全/不明智的。有一些安全的方法可以做到这一点吗?如果我只能说“更改当前路径但不重新加载 Controller ”,则事情将变得非常简单。
选项#4是否可行/可行?如果没有,那么还有更好的方法吗?也许有些神奇的“以 Angular 方式执行,但是以某种方式不会刷新 Controller ”吗?
最佳答案
这不是成 Angular 方式,但可能很有用。接收数据后,您可以检查是否有一个重点突出的元素(用户正在键入)。如果是这样,那么您需要定义一个在元素失去焦点时立即执行的函数。如果没有焦点元素,则立即更改URL。
像这样:ECardService.autosave($scope.eCard).then(function (response) {
if($(':focus').length){ //if there is focused element
$(':focus').one('blur', function(){ //
$location.path('/ecard/' + response.id).replace(); //perform once
});
}
else{
$location.path('/ecard/' + response.id).replace();
}
});
当然,这不是最优雅的解决方案,但似乎可以解决您的问题。