在AngularJS中,您可以在不重新加载控制器的情况下更改路径吗?

在AngularJS中,您可以在不重新加载控制器的情况下更改路径吗?,angularjs,Angularjs,以前有人问过这个问题,从答案来看不太好。我想在考虑这个示例代码时询问 我的应用程序在提供它的服务中加载当前项目。有几个控制器可以在不重新加载项目的情况下操作项目数据 如果项目尚未设置,“我的控制器”将重新加载该项目,否则,它将在控制器之间使用当前从服务加载的项目 问题:我希望在不重新加载Item.html的情况下为每个控制器使用不同的路径 1) 可能吗 2) 如果这是不可能的,那么与我在这里提出的方法相比,有没有更好的方法让每个控制器都有一个路径 app.js var-app=angular.m

以前有人问过这个问题,从答案来看不太好。我想在考虑这个示例代码时询问

我的应用程序在提供它的服务中加载当前项目。有几个控制器可以在不重新加载项目的情况下操作项目数据

如果项目尚未设置,“我的控制器”将重新加载该项目,否则,它将在控制器之间使用当前从服务加载的项目

问题:我希望在不重新加载Item.html的情况下为每个控制器使用不同的路径

1) 可能吗

2) 如果这是不可能的,那么与我在这里提出的方法相比,有没有更好的方法让每个控制器都有一个路径

app.js

var-app=angular.module('myModule',[])。
配置(['$routeProvider',函数($routeProvider){
$routeProvider。
when('/items',{templateUrl:'partials/items.html',controller:ItemsCtrl})。
当('/items/:itemId/foo',{templateUrl:'partials/item.html',controller:ItemFooCtrl})时。
当('/items/:itemId/bar',{templateUrl:'partials/item.html',controller:ItemBarCtrl})时。
否则({重定向到:'/items'});
}]);
Item.html


controller.js

//刷新或直接链接时加载$scope.item的Helper函数
函数itemCtrlInit($scope、$routeParams、MyService){
$scope.item=MyService.currentItem;
如果(!$scope.item){
MyService.currentItem=MyService.get({itemId:$routeParams.itemId});
$scope.item=MyService.currentItem;
}
}
函数itemFooCtrl($scope、$routeParams、MyService){
$scope.view={name:'foo',template:'partials/itemFoo.html'};
itemCtrlInit($scope、$routeParams、MyService);
}
函数itemBarCtrl($scope、$routeParams、MyService){
$scope.view={name:'bar',template:'partials/itemBar.html'};
itemCtrlInit($scope、$routeParams、MyService);
}
分辨率。

$location.path('/edit_draft_inbox/'+id, false);
状态:使用已接受答案中建议的搜索查询,可以在不重新加载主控制器的情况下提供不同的URL

app.js

var-app=angular.module('myModule',[])。
配置(['$routeProvider',函数($routeProvider){
$routeProvider。
when('/items',{templateUrl:'partials/items.html',controller:ItemsCtrl})。
当(“/item/:itemId/”,{templateUrl:'partials/item.html',controller:ItemCtrl,reloadOnSearch:false})时。
否则({重定向到:'/items'});
}]);
Item.html


controller.js

function ItemCtrl($scope、$routeParams、Appts){
$scope.views={
foo:{name:'foo',template:'partials/itemFoo.html'},
bar:{name:'bar',template:'partials/itemBar.html'},
}
$scope.view=$scope.views[$routeParams.view];
}
指令.js

app.directive('itemTab',function(){
返回函数(范围、元素、属性){
范围.$watch(attrs.itemTab,函数(val){
if(val+'Tab'==attrs.id){
元素addClass(“活动”);
}否则{
元素移除类(“活动”);
}
});
}
});

如果您不必使用像
#/item/{{item.id}/foo
#/item/{item.id}/bar
这样的URL,我的分区中的内容将用
ng controller=…

包装,但是
#/item/{item.id}/{foo
/item/{item.id}/bar/{code>可以为您的项目设置路由/
重新加载搜索设置为
false
()。这告诉AngularJS,如果url的搜索部分发生变化,就不要重新加载视图。

尽管这篇文章很旧,并且已经有了一个被接受的答案,但对于我们这些需要更改实际路径而不仅仅是参数的人来说,使用reloadOnSeach=false并不能解决问题。下面是一个简单的解决方案:

使用ng include而不是ng view,并在模板中指定控制器

<!-- In your index.html - instead of using ng-view -->
<div ng-include="templateUrl"></div>

<!-- In your template specified by app.config -->
<div ng-controller="MyController">{{variableInMyController}}</div>

//in config
$routeProvider
  .when('/my/page/route/:id', { 
    templateUrl: 'myPage.html', 
  })

//in top level controller with $route injected
$scope.templateUrl = ''

$scope.$on('$routeChangeSuccess',function(){
  $scope.templateUrl = $route.current.templateUrl;
})

//in controller that doesn't reload
$scope.$on('$routeChangeSuccess',function(){
  //update your scope based on new $routeParams
})

{{variableInMyController}}
//在配置中
$routeProvider
.when('/my/page/route/:id',{
templateUrl:'myPage.html',
})
//在顶级控制器中注入$route
$scope.templateUrl=“”
$scope.$on(“$routeChangeSuccess”,函数(){
$scope.templateUrl=$route.current.templateUrl;
})
//在不重新加载的控制器中
$scope.$on(“$routeChangeSuccess”,函数(){
//根据新的$routeParams更新您的范围
})
唯一的缺点是不能使用resolve属性,但这很容易解决。此外,您还必须管理控制器的状态,就像基于$routeParams的逻辑一样,当控制器内的路由随着相应url的更改而更改时


下面是一个示例:

如果需要更改路径,请在应用程序文件中的.config之后添加此选项。 然后可以执行
$location.path('/sampleurl',false)以防止重新加载

app.run(['$route', '$rootScope', '$location', function ($route, $rootScope, $location) {
    var original = $location.path;
    $location.path = function (path, reload) {
        if (reload === false) {
            var lastRoute = $route.current;
            var un = $rootScope.$on('$locationChangeSuccess', function () {
                $route.current = lastRoute;
                un();
            });
        }
        return original.apply($location, [path]);
    };
}])

我发现的最优雅的解决方案值得称赞。

为什么不把ng控制器提高一级

<body ng-controller="ProjectController">
    <div ng-view><div>
它适合我。

适合那些需要在不重新加载控制器的情况下更改path()的人- 以下是插件:

用法:

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

基于

注意:此解决方案包含错误 调用路径(,false)后-它将中断浏览器的向后/向前导航,直到调用路径(,true)

我使用此解决方案

angular.module('reload-service.module', [])
.factory('reloadService', function($route,$timeout, $location) {
  return {
     preventReload: function($scope, navigateCallback) {
        var lastRoute = $route.current;

        $scope.$on('$locationChangeSuccess', function() {
           if (lastRoute.$$route.templateUrl === $route.current.$$route.templateUrl) {
              var routeParams = angular.copy($route.current.params);
              $route.current = lastRoute;
              navigateCallback(routeParams);
           }
        });
     }
  };
})

//usage
.controller('noReloadController', function($scope, $routeParams, reloadService) {
     $scope.routeParams = $routeParams;

     reloadService.preventReload($scope, function(newParams) {
        $scope.routeParams = newParams;
     });
});

这种方法保留了后退按钮功能,并且与我见过的其他方法不同,模板中始终有当前路线图。

以下是我的更全面的解决方案,它解决了@Vigrond和@rahilwazir遗漏的一些问题:

  • 更改搜索参数时,将阻止广播
    $routeUpdate
  • 当路由实际上保持不变时,
    $locationChangeSuccess
    将不会触发,这将导致阻止下一次路由更新
  • 如果在同一个摘要周期中有另一个更新请求,这次希望重新加载,则事件处理程序将取消该重新加载
    app.run(['$rootScope', '$route', '$location', '$timeout', function ($rootScope, $route, $location, $timeout) {
        ['url', 'path'].forEach(function (method) {
            var original = $location[method];
            var requestId = 0;
            $location[method] = function (param, reload) {
                // getter
                if (!param) return original.call($location);
    
                # only last call allowed to do things in one digest cycle
                var currentRequestId = ++requestId;
                if (reload === false) {
                    var lastRoute = $route.current;
                    // intercept ONLY the next $locateChangeSuccess
                    var un = $rootScope.$on('$locationChangeSuccess', function () {
                        un();
                        if (requestId !== currentRequestId) return;
    
                        if (!angular.equals($route.current.params, lastRoute.params)) {
                            // this should always be broadcast when params change
                            $rootScope.$broadcast('$routeUpdate');
                        }
                        var current = $route.current;
                        $route.current = lastRoute;
                        // make a route change to the previous route work
                        $timeout(function() {
                            if (requestId !== currentRequestId) return;
                            $route.current = current;
                        });
                    });
                    // if it didn't fire for some reason, don't intercept the next one
                    $timeout(un);
                }
                return original.call($location, param);
            };
        });
    }]);
    
    .when('/:param1/:param2?/:param3?', {
        templateUrl: 'home.html',
        controller: 'HomeController',
        controllerAs: 'vm',
        noReload: true
    })
    
    fooRun.$inject = ['$rootScope', '$route', '$routeParams'];
    
    function fooRun($rootScope, $route, $routeParams) {
        $rootScope.$on('$routeChangeStart', function (event, nextRoute, lastRoute) {
            if (lastRoute && nextRoute.noReload 
             && lastRoute.controller === nextRoute.controller) {
                var un = $rootScope.$on('$locationChangeSuccess', function () {
                    un();
                    // Broadcast routeUpdate if params changed. Also update
                    // $routeParams accordingly
                    if (!angular.equals($route.current.params, lastRoute.params)) {
                        lastRoute.params = nextRoute.params;
                        angular.copy(lastRoute.params, $routeParams);
                        $rootScope.$broadcast('$routeUpdate', lastRoute);
                    }
                    // Prevent reload of controller by setting current
                    // route to the previous one.
                    $route.current = lastRoute;
                });
            }
        });
    }
    
    HomeController.$inject = ['$scope', '$routeParams'];
    
    function HomeController($scope, $routeParams) {
        //(...)
    
        $scope.$on("$routeUpdate", function handler(route) {
            // Do whatever you need to do with new $routeParams
            // You can also access the route from the parameter passed
            // to the event
        });
    
        //(...)
    }
    
      <script type="text/javascript">
        angular.element(document.getElementsByTagName('head')).append(angular.element('<base href="' + window.location.pathname + '" />'));
      </script>
    
    URL is - http://localhost:9000/#/edit_draft_inbox/1457
    
    $location.path('/edit_draft_inbox/'+id, false);
    
    $location.path('/items');
    $location.replace();
    
    window.localStorage['routeChangeWithoutReloadTimestamp'] = new Date().getTime();
    $location.path(myURL);
    
    .when(myURL, {
                templateUrl: 'main.html',
                controller:'MainCtrl',
                controllerAs: 'vm',
                reloadOnSearch: false,
                resolve:
                {
                    var routeChangeWithoutReloadTimestamp =
                        window.localStorage['routeChangeWithoutReloadTimestamp'];
                    var currentTimestamp = new Date().getTime();
                    if (!routeChangeWithoutReloadTimestamp ||
                            currentTimestamp - routeChangeWithoutReloadTimestamp >= 5000) {
                        //initialization code here
                    }
                    //reset the timestamp to trigger initialization when needed
                    window.localStorage['routeChangeWithoutReloadTimestamp'] = 0;
                }
    });