你能在AngularJS中不重新加载控制器的情况下更改路径吗?

13 浏览
0 Comments

你能在AngularJS中不重新加载控制器的情况下更改路径吗?

这个问题之前已经问过了,从答案来看情况不太乐观。我想在考虑这个示例代码的基础上再次提问...\n我的应用程序在提供服务的同时加载当前项。有几个控制器可以操作项的数据,而无需重新加载项。\n如果项尚未设置,我的控制器将重新加载该项,否则将在控制器之间使用当前加载的项。\n问题:我想为每个控制器使用不同的路径,而不重新加载Item.html。\n1)这可能吗?\n2)如果不可能,有没有更好的方法来实现每个控制器的路径,而不像我在这里想出的那样重新加载?\napp.js\n

var app = angular.module('myModule', []).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/items', {templateUrl: 'partials/items.html',   controller: ItemsCtrl}).
      when('/items/:itemId/foo', {templateUrl: 'partials/item.html', controller: ItemFooCtrl}).
      when('/items/:itemId/bar', {templateUrl: 'partials/item.html', controller: ItemBarCtrl}).
      otherwise({redirectTo: '/items'});
    }]);

\nItem.html\n


Foo
Bar

\ncontroller.js\n

// 用于加载$scope.item的辅助函数,如果是刷新或直接链接
function itemCtrlInit($scope, $routeParams, MyService) {
  $scope.item = MyService.currentItem;
  if (!$scope.item) {
    MyService.currentItem = MyService.get({itemId: $routeParams.itemId});
    $scope.item = MyService.currentItem;
  }
}
function itemFooCtrl($scope, $routeParams, MyService) {
  $scope.view = {name: 'foo', template: 'partials/itemFoo.html'};
  itemCtrlInit($scope, $routeParams, MyService);
}
function itemBarCtrl($scope, $routeParams, MyService) {
  $scope.view = {name: 'bar', template: 'partials/itemBar.html'};
  itemCtrlInit($scope, $routeParams, MyService);
}

\n解决方案。\n状态:根据接受的答案中建议的使用搜索查询的方法,我能够在不重新加载主控制器的情况下提供不同的URL。\napp.js\n

var app = angular.module('myModule', []).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/items', {templateUrl: 'partials/items.html',   controller: ItemsCtrl}).
      when('/item/:itemId/', {templateUrl: 'partials/item.html', controller: ItemCtrl, reloadOnSearch: false}).
      otherwise({redirectTo: '/items'});
    }]);

\nItem.html\n


Foo
Bar

\ncontroller.js\n

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

\ndirectives.js\n

app.directive('itemTab', function(){
  return function(scope, elem, attrs) {
    scope.$watch(attrs.itemTab, function(val) {
      if (val+'Tab' == attrs.id) {
        elem.addClass('active');
      } else {
        elem.removeClass('active');
      }
    });
  }
});

\n我的partials中的内容被包裹在ng-controller=...中。

0
0 Comments

问题的出现原因是在AngularJS中改变路径时会重新加载控制器,而有些情况下我们不希望重新加载控制器。解决方法是将ng-controller指令放在更高一级的元素上,并且在路由中不设置控制器。这样可以避免控制器的重新加载。另外,如果需要在控制器中读取$routeParams的值,可以在$routeChangeSuccess事件处理程序中进行读取。下面是一个示例代码:

<body ng-controller="ProjectController">
    <div ng-view><div>

.when('/', { templateUrl: "abc.html" })

通过上述方法可以实现在改变路径时不重新加载控制器,同时能够读取$routeParams的值。这是一种解决该问题的有效方法。

0
0 Comments

在AngularJS中,当我们需要更改路径而不重新加载控制器时,可以使用以下方法:

在应用程序文件的.config之后添加以下内容:

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

这个方法的原理是,当设置reload参数为false时,它会在$locationChangeSuccess事件中将$route.current设置回上一个路由,从而实现改变路径而不重新加载控制器的效果。

这个方法的来源是https://www.consolelog.io/angularjs-change-path-without-reloading,这是我找到的最优雅的解决方法。

不过需要注意的是,这个解决方法会保留旧的路由,如果你请求$route.current,你会得到之前的路径,而不是当前的路径。但是总体来说,这是一个非常好的技巧。

某些情况下是否有办法让浏览器的后退按钮“遵循”这个方法,但是没有给出具体的解决方案。

还某些情况下,这个方法仍然会重新加载视图。

还某些情况下,使用这个方法后,有些$scope变量在路由改变后无法使用,所以需要重新创建所有的对象和变量。

也有人问是否可以在ui-router中实现相同的功能,但是没有给出具体的解决方案。

有人分享了自己的解决方案,并补充了一些之前方法中没有的内容。

这个方法在AngularJS 1.5中运行良好。

总结一下,这个问题的出现是因为在AngularJS中更改路径时会重新加载控制器,而解决方法是通过修改$location.path的方式来实现改变路径而不重新加载控制器。

0
0 Comments

在AngularJS中,有时我们希望在不重新加载控制器的情况下更改路径。一个用户在论坛上提问了这个问题,他的需求是将路径中的#/item/{{item.id}}/foo#/item/{{item.id}}/bar改为#/item/{{item.id}}/?foo#/item/{{item.id}}/?bar。有人回答说,可以在/item/{{item.id}}/的路由上设置reloadOnSearch属性为false,这样当url的搜索部分发生变化时,AngularJS就不会重新加载视图。

另一个用户回答说,你可以在itemCtrlInit中创建一个对$location.search()进行监视的方法,并根据搜索参数的不同更新$scope.view.template。然后,可以用<div ng-controller="itemFooCtrl">... your template content...</div>来包装这些模板。该用户还建议用户将问题的解决方案更新到问题中,以便其他人也可以获得帮助。

原问题提问者表示,他会在解决问题后将解决方案更新到问题中。他还提到了自己遇到的作用域问题,并表示会在稍后解决。另一个用户提醒他可以使用jsFiddle/plnkr等工具来创建多个片段。原问题提问者表示感谢,并表示这些回答确实指导了他正确的方向。

最后,有人指出其实不需要重新格式化URL,因为AngularJS的文档中已经提到了reloadOnSearch参数可以实现在搜索参数变化时重新加载路由。还某些情况下在UI Router中也存在相同的参数。

这个讨论中还有其他一些用户的回答和问题,但与原问题的解决方案无关。这个讨论给出了在AngularJS中如何在不重新加载控制器的情况下更改路径的解决方法。

0