AngularJS:更改哈希和路由,而不需要完全重新加载控制器(AngularJS: Change

2019-06-27 08:35发布

我有一个控制器,像这样的路线:

#/用品/ 1234

我想改变路线而没有完全重装控制器,这样我就可以继续其他的东西在控制器恒定位置(即滚动列表)

我能想到的几个方法可以做到这一点,但他们都非常难看。 有没有做这样的事情最好的做法? 我试着用reloadOnSearch试验:假的,但它似乎并没有改变任何东西。

Answer 1:

有同样的challange,

发现在一劈另一StackOverflow的响应该诀窍

还算干净的解决方案 - 我所做的就是将这些行添加到设置$ location.path控制器:

var lastRoute = $route.current;
$scope.$on('$locationChangeSuccess', function(event) {
    $route.current = lastRoute;
});

..和在确信$途径注入过程的控制。

但尽管如此,感觉像“DoNotFollowRoutesOnPathChange”是AngularJS缺少功能。

/延

更新:自从听了这个活动有效地杀死$ routeProvider CONFIGS的进一步使用,我不得不这样抓限制为仅当前路径:

    var lastRoute = $route.current;
    if ($route.current.$route.templateUrl.indexOf('mycurrentpath') > 0) {
        $route.current = lastRoute;         
    }

变丑...



Answer 2:

简要回答:

您可以使用$location.search()如你所提到的方法。 你应该听"$routeUpdate"的范围,而不是其他途径事件的事件。 $路线API 。

说明:

  1. 首先,(你已经知道),加reloadOnSearch: false到您的$routeProvider

     $routeProvider.when('/somewhere', { controller: 'SomeCtrl', reloadOnSearch: false }) 
  2. 改变你的锚标记hrefng-hrefhref="#/somewhere?param=value"这将触发$routeChangeSuccess事件,如果路径部分( /somewhere )是不一样的当前位置。 否则会引发$routeUpdate事件。

  3. 监听范围的事件:

     $scope.$on("$routeUpdate", function(event, route) { // some code here }); 
  4. 如果你想改变搜索PARAMS在代码中,你可以使用$location.search()方法。 $ location.search API 。



Answer 3:

如果设置reloadOnSearch为false,您可以设置?a=b&c=d不重装的URL的一部分。 你不能改变娇滴滴的实际位置,虽然没有重装。



Answer 4:

编辑

使用ngRoute时更好的方法:

/**
 * Add skipReload() to $location service.
 *
 * See https://github.com/angular/angular.js/issues/1699
 */
app.factory('location',
  ['$rootScope', '$route', '$location',
  function($rootScope, $route, $location) {

  $location.skipReload = function() {
    var lastRoute = $route.current;

    var deregister = $rootScope.$on('$locationChangeSuccess',
                                    function(e, absUrl, oldUrl) {
      console.log('location.skipReload', 'absUrl:', absUrl, 'oldUrl:', oldUrl);
      $route.current = lastRoute;
      deregister();
    });

    return $location;
  };

  return $location;
}]);

如何使用:

app.controller('MyCtrl', ['$scope', 'location', function($scope, location) {
  $scope.submit = function() {
    location.skipReload().path(path);
  };
}]);

老答案

我写了一个可重复使用的工厂,基于延X Augustsson答案:

app.factory('DoNotReloadCurrentTemplate', ['$route', function($route) {
  return function(scope) {
    var lastRoute = $route.current;
    scope.$on('$locationChangeSuccess', function() {
      if (lastRoute.$$route.templateUrl === $route.current.$$route.templateUrl) {
        console.log('DoNotReloadCurrentTemplate',
                    $route.current.$$route.templateUrl);
        $route.current = lastRoute;
      }
    });
  };
}]);

与AngularJS 1.0.6工程

如何使用:

app.controller('MyCtrl',
  ['$scope', 'DoNotReloadCurrentTemplate',
  function($scope, DoNotReloadCurrentTemplate) {

  DoNotReloadCurrentTemplate($scope);
}]);

这里AngularJS问题: https://github.com/angular/angular.js/issues/1699



Answer 5:

定义一个工厂来处理HTML5的的window.history像这样(注意,我把一个自己的堆栈,使其适用于Android,以及因为它有一些问题存在):

.factory('History', function($rootScope) {
    var StateQueue = [];
    var StatePointer = 0;
    var State = undefined;
    window.onpopstate = function(){
        // called when back button is pressed
        State = StateQueue.pop();
        State = (State)?State:{};
        StatePointer = (StatePointer)?StatePointer-1:0;
        $rootScope.$broadcast('historyStateChanged', State);
        window.onpopstate = window.onpopstate;

    }
    return {
        replaceState : function(data, title, url) {
            // replace current state
            var State = this.state();
            State = {state : data};
            window.history.replaceState(State,title,url);
            StateQueue[StatePointer] = State;
            $rootScope.$broadcast('historyStateChanged', this.state());
        },
        pushState : function(data, title, url){
            // push state and increase pointer
            var State = this.state();
            State = {state : data};
            window.history.pushState(State,title,url);
            StateQueue.push(State);
            $rootScope.$broadcast('historyStateChanged', this.state());
            StatePointer ++;
        },
        fakePush : function(data, title, url) {
            // call this when you do location.url(url)
            StateQueue.push((StateQueue.length - 1 >= 0)?StateQueue[StateQueue.length -1]:{});
            StatePointer ++;
            $rootScope.$broadcast('historyStateChanged', this.state());
        },
        state : function() {
            // get current state
            return (StateQueue[StatePointer])?StateQueue[StatePointer]:{};
        },
        popState : function(data) {
            // TODO manually popState
        },
        back : function(data) {
            // TODO needed for iphone support since iphone doesnt have a back button
        }
    }
})

增加您的依赖范围的几个听众,你会没事的,像这样:

$scope.$on('historyStateChanged', function(e,v) {
        if(v)
            $scope.state = v;
        else
            $scope.state = {}
    });

这就是我如何做到这一点。 在我的角度来看,当一个新的视图中加载的URL应该只改变。 我认为是对角队打算如何它反正。 如果你想映射着你的模型/后退按钮尝试用HTML5的的window.history做

希望我能帮上忙。 干杯,海因里希



Answer 6:

使用:

$routeProvider.when('/somewhere', {
    controller: 'SomeCtrl',
    reloadOnSearch: false
})

这将防止重装上查询参数变化的控制器,同时也对哈希变化。



Answer 7:

如果你在2015年的土地位置:这里真正的答案是使用没有这些黑客的(我敢说他们的名字是这样,因为使用任何你上面列出的方法就失去了使用的决心和喜欢的可能性),但切换到UI的路由器 。

下面是对差异的方便演示。 实现应尽可能交换$路线$状态和转换各州的名字一样简单。

我目前正在切换到的方法就是我与一个A HREF指的路线,以改变国家无需重新加载它一个可选的GET参数。 欲了解更多关于这一点,看看“PARAMS”部分在这里



Answer 8:

这个简单的解决方案(奇怪)为我工作:

$state.params.id = id;  //updating the $state.params somehow prevents reloading the state
$location.path('/articles/' + id);

它不会阻止状态重装上后退和前进按钮虽然。 注:我使用angularjs 1.2.7和UI路由器0.0.1(我知道这是旧的)。



Answer 9:

下面是插件: https://github.com/anglibs/angular-location-update

用法:

$location.update_path('/notes/1');


Answer 10:

你可以这样做,而不$locationChange~HistoryState使用黑客route小号resolve承诺的选择。

假设你有一个article ,途径,这个数字是什么改变了你可以做到这一点;

$routeProvider.when(
    '/article/:number',
    {
        templateUrl : 'partial.html',
        controller : 'ArticleCtrl',
        resolve : {
            load : ['$q', '$routeParams', function($q, $routeParams) {
                var defer = $q.defer();

                //number was specified in the previous route parameters, means we were already on the article page
                if ($routeParams.number)
                    //so dont reload the view
                    defer.reject('');
                //otherwise, the number argument was missing, we came to this location from another route, load the view
                else
                    defer.resolve();

                return defer.promise;
            }]
        }
    }
);


文章来源: AngularJS: Change hash and route without completely reloading controller