刷新使用AngularJS的ngview(F5)

5
我有一个关于我的Angular应用程序的问题。第一次运行应用程序时,可以在内部导航,但是当我尝试使用F5刷新页面时,它会失败。按下F5键时,部分内容被调用到服务器上,并且服务器显然会响应部分视图,但不是整个应用程序。
节点路由:
app.get('/', node_routes.welcome);
...
app.get('/profile', pass.ensureAuthenticated, profile_routes.profile);
app.get('/profile/:name', pass.ensureAuthenticated, profile_routes.partials);
app.post('/profile/update', pass.ensureAuthenticated, profile_routes.update);
...

控制器:

exports.profile = function(req, res) {
    var user = req.user;
    Profile.findOne({ username: user.username }, function(err, profile) {
        if (err) { 
            res.redirect('/'); 
        }       
        res.render("profile");
    });  
};  

exports.partials = function(req, res) {
    var name = req.params.name;
    var user = req.user;
    Profile.findOne({ username: user.username }, function(err, profile) {
        if (err) { 
            res.redirect('/'); 
        }       
        res.render(path.join(__dirname + '/../views/profile/' + name));
    });
};

exports.update = function(req, res){
    var profile = req.body;
    delete profile._id;
    Profile.update({'username':profile.username},profile,{safe:true}, function(err, result){
        if(err) {
            console.log('Error updating profile. ' + err);
            res.redirect('/profile');
        }
        else{
            console.log('' + result + ' profile updated for user: ' + profile.username);
            res.redirect('/profile');
        }           
    });
};

Angular 应用程序

myApp.config(['$routeProvider','$locationProvider', function($routeProvider,$locationProvider){
    $routeProvider
       .when('/profile/update', {
           controller: 'myJobOfferListCtrl',
           templateUrl: '/profile/update',
           reloadOnSearch: false
       })
       .when('/profile', {
           controller: 'myJobOfferListCtrl',
           templateUrl: '/profile/dashboard'
       })
       .when('/profile/dashboard', {
           controller: 'myJobOfferListCtrl',
           templateUrl: '/profile/dashboard',
           reloadOnSearch: false
       })
       .when('/profile/offers', {
           controller: 'myJobOfferListCtrl',
           templateUrl: '/profile/offers',
           reloadOnSearch: false
       })      
       .otherwise({redirectTo: '/profile'});
    $locationProvider.html5Mode(true);
}]);

我的个人资料页面
extends layout

block content   
   div.container-fluid(ng-app="appProfile", ng-controller="myJobOfferListCtrl", ng-init="initProfile()")
      div.row-fluid
         div.span3(ng-controller="navBarCtrl")
           div.well.sidebar-nav
             ul.nav.nav-list
               li.well.nav-header.
                  My Profile ({{data.profile.username}})
               li(ng-class="{ active: isActive('dashboard')}") 
                  a(href="/profile/dashboard") Dashboard   
               li(ng-class="{ active: isActive('update')}") 
                  a(href="/profile/update") Update profile
               li.divider
               li.well.nav-header My Jobs
               li(ng-class="{ active: isActive('offers')}") 
                  a(href="/profile/offers") Offers
               li(ng-class="{ active: isActive('application')}") 
                  a(href="/profile/application") Applications
         div.span9(ng-view, ng-cloak)

这是一个示例局部视图页面

   div.row-fluid 
      div(ng-init="initMyOffers()")  
         accordion.span8.offset1(close-others="true")
            accordion-group(ng-repeat="item in data.myJobs", heading="{{item.title}}")
               accordion-heading
                  {{item.title}}
                  i.pull-right.icon-remove-circle.removeButton(ng:click="remove(item)") 
               p {{item.description}}
               hr
               div.footer
                  div.pull-left 
                     i.icon-calendar.calendar
                     {{item.dueDate | date:'d MMMM yyyy'}}
                  div.pull-right 
                     i.icon-user 
                     {{item.author}}

我该如何在按下F5时重新加载页面的部分内容?对于Angular框架,我期望的是当试图刷新例如页面/profile/dashboard时,局部视图/views/profile/dashboard.jade被调用,但也会调用views/profile.jade。至于$scope,它会被保留吗?
抱歉,我有点困惑...感谢您的帮助!

一个简单的解决方案是关闭HTML5路由:$locationProvider.html5Mode(false) - musically_ut
3个回答

4

我认为这是一个常见的问题,用户不应该在你的应用程序中使用 F5。我认为,在按下 F5 后停止默认浏览器操作是不可能的。

一个简单的解决方案是在每个视图中添加此或类似的 script

<script>
    if (angular == undefined)
        // alert("It is SPA (Single Page Application) -- do not press F5 anymore, please.");
        window.location.replace("your/main/url");
</script>

稍微复杂一些的情况是实现以下场景。
  1. 用户按下 f5
  2. 服务器发送当前URL current_url 的部分视图
  3. 客户端检测到缺少 angular 并发送请求以重定向到 current_url
  4. 服务器发送修改后的 index.html 文件 [例如,包含某个隐藏的输入字段,用于存储 current_url]
  5. 在加载了 Angular 后,应用程序检查隐藏字段并相应地更改位置

2
我认为,如果刷新页面会带用户回到主页面并显示令人沮丧的警告信息,这将导致非常糟糕的用户体验。用户应该被允许重新加载页面,而应用程序应该能够正常工作。然而,在某些情况下,这是不可能的,告诉用户不要执行这些操作可能是最好的选择,但对于每个单页应用程序来说肯定不是。 - musically_ut
@musically_ut 这句话本意是开玩笑的,当然它非常依赖于上下文。但我已经注释掉了。 - artur grzesiak
好的,如果我理解正确,没有“简单”的方法来处理刷新...我必须捕获Angular未加载并强制重新加载主视图,然后重定向到要重新加载的页面。不是很容易,有点棘手。希望Angular有这样的嵌入式功能,但我理解“用户不应该刷新”,但如果情况确实如此,应用程序不应该失败! - GuillaumeA
1
@G_A 问题在于,点击“刷新”会清除当前选项卡中的所有状态。这与Angular本身无关,而是浏览器中的JavaScript应该如何工作。顺便说一句,我的建议可能是最基本的。您可以将应用程序的状态存储在cookie或其他永久性存储(使用HTML5),因此您可以在重新加载后对应用程序的状态进行重建。但在大多数情况下,这可能不值得做。 - artur grzesiak
我想要的第一件事是应用程序不会失败。因此,我认为在检测到不是从Angular调用时重定向到“main”视图。暂时不考虑当前状态是否被清除,作为第一步,这是一个完全合适的方法。 - GuillaumeA

2

当刷新Angular应用时,避免丢失数据的最简单、最优雅的方法是使用$cookies服务将所需值存储在cookie中。以下是一个示例。希望这能帮到你。

"use strict";
angular.module('myApp').factory('SessionSrv', [ '$cookies', function($cookies){

    var _myString = $cookies.get('myString'); // e.g. "foo"
    var _myObject = $cookies.getObject('myObject'); // e.g. {foo: "bar"}

    return {

        setMyString: function(myString){
            _myString = myString;
            $cookies.put('myString', _myString);
        },

        getMyString: function(){
            return _myString;
        },

        setMyObject: function(myObject){
            _myObject = myObject;
            $cookies.putObject('myObject', _myObject);
        },

        getMyObject: function(){
            return _myObject;
        },

    };
}]);

1

最终按照artur的建议实现了解决方案:

<script>
  if (typeof angular == 'undefined')
     window.location.replace("/main_url");
</script>

如果你只是想说他的答案解决了你的问题,为什么不直接接受他的答案呢?我不太确定为什么你不能这样做。 - BoltClock
2
因为存在一些差异,而且他的解决方案并没有像原样那样起作用。 - GuillaumeA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接