Переключить видимость ng-include в зависимости от маршрута

У меня следующая конфигурация:

$routeProvider
.when('/cars', { templateUrl: 'app/cars/index.html', controller: 'CarsCtrl', reloadOnSearch: false })
.when('/bikes', { templateUrl: 'app/bikes/index.html', controller: 'BikesCtrl', reloadOnSearch: false });

и где-то в моем корневом index.html есть:

<a href="#/cars">Cars</a>
<a href="#/bikes">Bikes</a>
<div ng-view></div>

Теперь я хочу, чтобы оба представления загружались и генерировались в DOM одновременно и отображали одно из них в зависимости от маршрута/URL.

Что-то вроде следующего (не настоящий рабочий код, просто чтобы дать вам представление).

приложение.js:

$routeProvider
.when('/cars', { controller: 'CarsCtrl', reloadOnSearch: false })
.when('/bikes', { controller: 'BikesCtrl', reloadOnSearch: false });

корень index.html:

<a href="#/cars">Cars</a>
<a href="#/bikes">Bikes</a>
<div ng-include="'app/cars/index.html'" ng-show="carsVisible"></div>
<div ng-include="'app/bikes/index.html'" ng-show="bikesVisible"></div>

ОБНОВЛЕНИЕ: я знаю, что ng-view делает это, но разница, пусть и тонкая, существует. Я хочу, чтобы html каждого представления генерировался один раз и всегда оставался в DOM.


person luisfarzati    schedule 28.02.2013    source источник
comment
Это невозможно сделать с помощью ng-view. Но вопрос в том, почему вы действительно хотите это сделать. Это потому, что вы хотели бы «предварительно обработать» каждый маршрут, чтобы он загружался быстрее? Маршрутизация уже выполняется довольно быстро, если вашим контроллерам не требуются некоторые асинхронные данные, и в этом случае вы должны использовать «разрешить» внутри объекта определения маршрута, а также некоторый код инициализации приложения для получения асинхронных данных в фоновом режиме.   -  person Stewie    schedule 28.02.2013


Ответы (4)


Я создал один RouteCtrl для загрузки всех ваших представлений через ng-include. ng-view не используется. Я вставил шаблоны. Шаблоны могут содержать свои собственные директивы ng-controller для получения определенных контроллеров.

<body ng-controller="RouteCtrl">
  <a href="#/cars">Cars</a>
  <a href="#/bikes">Bikes</a>
  <div ng-controller="RouteCtrl">
      <div ng-include="'/cars.html'"  ng-show="carsVisible"></div>
      <div ng-include="'/bikes.html'" ng-show="bikesVisible"></div>
  </div>

  <script type="text/ng-template" id="/cars.html">
     Cars template.
  </script> 
  <script type="text/ng-template" id="/bikes.html">
     Bikes template.
  </script> 

$routeProvider по-прежнему настроен, но не указан ни шаблон, ни контроллер, поэтому RouteCtrl всегда активен. Этот контроллер прослушивает событие $routeChangeSuccess и соответствующим образом манипулирует свойствами ng-show.

app.config(function($routeProvider) {
  $routeProvider
     .when('/cars', {} )
     .when('/bikes', {})
});

app.controller('RouteCtrl', function($scope, $route, $location) {
  $scope.$on('$routeChangeSuccess', function() {
    var path = $location.path();
    console.log(path);
    $scope.carsVisible = false;
    $scope.bikesVisible = false;
    if(path === '/cars') {
       $scope.carsVisible = true;
    } else if(path === '/bikes') {
       $scope.bikesVisible = true;
    }
  });
});

Планкер

Идея этого решения принадлежит @Andy.

person Mark Rajcok    schedule 02.03.2013

Я нашел другой способ, который я считаю самым простым, быстрым и управляемым:

Как установить активный класс навигационной панели начальной загрузки с помощью Угловой JS?

Который:

Используйте ng-controller для запуска одного контроллера вне ng-view:

<div class="collapse navbar-collapse" ng-controller="HeaderController">
    <ul class="nav navbar-nav">
        <li ng-class="{ active: isActive('/')}"><a href="/">Home</a></li>
        <li ng-class="{ active: isActive('/dogs')}"><a href="/dogs">Dogs</a></li>
        <li ng-class="{ active: isActive('/cats')}"><a href="/cats">Cats</a></li>
    </ul>
</div>
<div ng-view></div>

и включить в controllers.js:

function HeaderController($scope, $location) 
{ 
    $scope.isActive = function (viewLocation) { 
        return viewLocation === $location.path();
    };
}
person Zymotik    schedule 23.06.2014

Вместо использования ng-include вы должны использовать ng-view;

Это отобразит содержимое либо app/cars/index.html, либо app/bikes/index.html

<a href="#/cars">Cars</a>
<a href="#/bikes">Bikes</a>
<div ng-view></div>

См. раздел Шаблон на странице http://docs.angularjs.org/tutorial/step_07

person Pascal Belloncle    schedule 28.02.2013
comment
Привет, Паскаль, спасибо за ответ! Однако это не то, что я ищу. Я внес уточнение в свой вопрос. ng-view будет переключать содержимое, да, но он делает это, удаляя содержимое из существующего представления и вставляя содержимое для нового представления каждый раз при изменении маршрута. Я хочу, чтобы оба содержимого уже отображались, и просто переключал одно или другое с помощью ng-show или отображения CSS. - person luisfarzati; 28.02.2013
comment
где/когда вы меняете carsVisible и bikesVisible , и есть ли у вас контроллер где-то в корне index.html? - person Pascal Belloncle; 28.02.2013

Используйте сервис с директивой show:

<div ng-show="myService.isActive('/')">Show this when at default route</div>
<div ng-show="myService.isActive('/cars')">Show this when at cars</div>

Услуга:

myApp.factory('MyService',
    function ($location) {
        return {
            isActive: function (path) {
                return (($location.path() == path));
            }
        }
    }
);

App.js:

// this is run after angular is instantiated and bootstrapped
myApp.run(function ($rootScope, myService) {
    $rootScope.breadcrumbService = MyService;
});
person Zymotik    schedule 28.02.2014