AngularJS: Change hash and route without completely reloading controller

前端 未结 10 1220
鱼传尺愫
鱼传尺愫 2020-12-07 19:29

I have a controller, with a route like this:

#/articles/1234

I want to change the route without completely reloading the controller, so I can keep the positi

相关标签:
10条回答
  • 2020-12-07 19:48

    Edit

    Better approach when using 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;
    }]);
    

    How to use:

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

    Old answer

    I have written a reusable factory for that based on Jens X Augustsson answer:

    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;
          }
        });
      };
    }]);
    

    Works with AngularJS 1.0.6

    How to use:

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

    AngularJS issue here: https://github.com/angular/angular.js/issues/1699

    0 讨论(0)
  • 2020-12-07 19:51

    You can do this without the $locationChange~ and HistoryState hacks using routes resolve promise option.

    Assuming you had an article route where that number is what changed you could do this;

    $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;
                }]
            }
        }
    );
    
    0 讨论(0)
  • 2020-12-07 19:54

    If you land here in 2015: The real answer here is to use none of these hacks (I dare name them so, because by using any of the methods listed above you will lose the possibility to use resolve and the likes) but to switch to ui-router.

    Here's a handy presentation on the differences. Implementation should be as simple as swapping $route for $state and converting the states to names.

    I'm currently switching over to a method where i will refer with an a href to a route, with an optional get parameter that changes the state without reloading it. For more on this, look at the 'params' section here

    0 讨论(0)
  • 2020-12-07 19:55

    This simple solution (surprisingly) works for me:

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

    It doesn't prevent the state reloading on Back and forward button though. Note: I'm using angularjs 1.2.7 and ui-router 0.0.1 (I know it's old).

    0 讨论(0)
  • 2020-12-07 19:57

    If you set reloadOnSearch to false, you can set the ?a=b&c=d portion of the url without reload. You can't change the actual location prettily, though, without a reload.

    0 讨论(0)
  • 2020-12-07 20:05

    Use:

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

    This will prevent reloading the controller on query parameter change, but also on hash change.

    0 讨论(0)
提交回复
热议问题