2015-06-09 2 views
2

Как я могу сохранить $location.search() с

$routeProvider.otherwise({redirectTo: xxx}) 

Я знаю, я могу использовать функцию там, который получает старый объект $location.search() в качестве третьего аргумента. В основном я забочусь об одном ключе, давайте назовем его a, и я попытался

function(a, b, search) { 
    return "/mainpage?a=" + search[a]; 
} 

но это всегда заканчивается /mainpage?a=undefined. Что еще хуже, это сбивает мой отладчик, что замедляет меня. Более того, это не работает для всех ключей (которые мне могут понадобиться позже).

ответ

2

Я сделал новый подход, в котором прослушивать $routeChangeStart и изменять search(), если содержащейся в предыдущей (несуществующей) странице важно GET параметры. Полный источник и демо можно найти на this Plunker.

Концепция похожа на решение @ Mikko, но реализация немного отличается (без специального поставщика), и она работает согласно инструкциям автора.

Сущность

angular.module('myApp').run(['$rootScope', '$location', 'URL', function($rootScope, $location, URL) { 

    // Previous search() value 
    var prevSearch = {}; 

    // Listen to event 
    $rootScope.$on('$routeChangeStart', function(evt, next, current) { 

     // Have search() parameters and are going to default route 
     if(prevSearch !== undefined && $location.path().endsWith(URL.defaultRoute)) { 

      // Extract only important params 
      var important = {}; 
      var importantCount = 0; 

      for(var param in prevSearch) { 

       if(URL.importantParams.indexOf(param) > -1) { 

        important[param] = prevSearch[param]; 
        importantCount++; 

       } 

      } 

      // Unset prevSearch 
      prevSearch = {}; 

      // Apply important params, if any 
      if(importantCount > 0) { 

       $location.search(important); 

      } 


     } else { 

      // Remember current search() 
      prevSearch = $location.search(); 

     } 

    }); 

}]); 

run функция устанавливает для слушателя $routeChangeStart, а также запоминает предыдущие значения величины search() (ГЭТ Params).

Когда приложение перенаправляется на маршрут по умолчанию, он проверяет предыдущее значение параметров search() и извлекает только важные. Если он есть, он переопределяет значение search() и поэтому задает важные параметры GET для маршрута по умолчанию.

Я установил константу URL, в которой можно установить маршрут по умолчанию и указать важные параметры. Код заключается в следующем:

angular.module('myApp').constant('URL', { 
    defaultRoute: '/mainpage', 
    importantParams: ['a', 'b'], 
}); 

демонстрационной

ссылка первого содержит 3 параметров на несуществующий URL. Страница правильно перенаправляется на маршрут по умолчанию, и сохраняются только 2 важных.

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

Ссылка Третья ссылка также содержит 3 параметра по маршруту по умолчанию, и все они сохраняются (перенаправление не происходит).

+0

Приятно слышать, что я вдохновил кого-то :)! Повторное использование в стороне, не следует переходить с «URL-адреса по умолчанию с параметрами», например, «Не существующие URL без параметров» по-прежнему сохраняют параметры? Другими словами, не существующий url с параметрами или без них всегда должен перенаправляться на 'main' с использованием параметров из последнего известного« хорошего »маршрута? –

+0

Я принял этот ответ, потому что он проще и награжден щедростью @MikkoViitala, когда он был первым. +++ Что касается использования параметров с последнего известного «хорошего» маршрута, мне на самом деле все равно. Пользователь приходит из другого места, используя ссылку, ведущую к 'http: //example.com? Important = 42', и я должен перенаправить их на http: //example.com/main? Important = 42'. Аналогичным случаем будет http: //example.com/non-existing-page? Important = 42'. Это все, что мне нужно сейчас, еще не подумал о более сложных случаях. Спасибо вам обоим! – maaartinus

1

Основная проблема заключается в том, что на этапе конфигурации (.config() функция) вы можете вводить только поставщиков. А поскольку $location не является поставщиком, вы не можете его вводить. Поэтому $location.search() не работает.

Чтобы получить параметры URL-адреса, вы можете использовать обычный коддля JavaScript. Но это не Угловой способ, и он не работает так, как вы бы хотели.

Например, если вы используете следующий код конфигурации:

angular.module('myApp').config(['$routeProvider', function($routeProvider) { 

    // Return $location.search() equivalent object 
    function locationSearch() { 

     var search = {}; 
     var hash = window.location.hash; 
     var index = hash.indexOf('?'); 

     // Has parameters 
     if(index > -1) { 

      // Extract only the params 
      var params = hash.substring(index + 1); 

      // Split parameters 
      params = params.split('&'); 

      var tmp; 
      for(var i = 0, len = params.length; i < len; i++) { 

       tmp = params[i].split('='); 
       search[tmp[0]] = tmp[1]; 

      } 

     } 

     return search; 

    } 

    // Generate default URL 
    function defaultURL(search) { 

     if(search.a === undefined) { 

      return '/mainpage'; 

     } else { 

      return '/mainpage?a=' + search.a; 

     } 

    } 

    // Equivalent of $location.search() 
    var search = locationSearch(); 

    // Set up routing 
    $routeProvider 

     // Events 
     .when('/test', { 
      templateUrl: 'test.html', 
      controller: 'TestCtrl' 
     }) 

     // Default page 
     .otherwise({ 
      redirectTo: defaultURL(search) 
     }); 

}]); 

С выше коде, вы можете получить доступ эквивалент $location.search() и скомпилировать динамический URL в качестве маршрута по умолчанию - НО ngRoute избегает его.

Например, функция defaultURL() производит примерно следующее: /mainpage?a=123. Однако ngRoute ускользает от специальных символов (т. Е. ? и &), и вы перенаправляетесь на /mainpage%3Fa=123, что не работает должным образом.

Кроме того, это работает только в том случае, если вы свежее открываете страницу с этим URL-адресом. Когда вы уже находитесь на странице и переходите на недействительный URL, вышеуказанный код не работает, поскольку фаза конфигурации уже выполнена - .config() срабатывает только один раз на загрузку страницы.

TL; DR

Насколько мне известно, это не может быть сделано с помощью метода $routeProvider.otherwise() внутри фазы конфигурации.

1

Вы можете создать свой собственный provider, который вы подключаете в течение config и run фаз, чтобы сохранить ваши параметры поиска.

Допустим, у вас есть следующие:

angular.module('app', ['ngRoute']) 
    .provider('myRoute', function myRouteProvider() { 
    var defaultUrl; 
    var search; 

    // get default url with params (config phase) 
    this.default = function() { 
     var params = ''; 
     angular.forEach(search, function(value, key) { 
     params = params + key + '=' + value + '&'; 
     }); 

     if (params.length > 0) { 
     params = params.substring(0, params.length - 1); 
     } 

     var redirectUrl = defaultUrl + (params ? '?' + params : ''); 
     console.log(redirectUrl); 
     return redirectUrl; 
    }; 

    this.$get = function($rootScope) { 
     var myRoute = {}; 

     // set default url (run phase) 
     myRoute.setDefault = function(url) { 
     if (defaultUrl) { 
      throw 'Provider already initialized'; 
     } 

     defaultUrl = url; 

     // update params on route change 
     $rootScope.$on('$routeChangeStart', function(event, next, current) { 
      search = current.params; 
     }); 
     }; 

     return myRoute;  
    }; 
    }) 

    .config(function($routeProvider, myRouteProvider) { 
    $routeProvider 
     .when('/main', { 
     templateUrl: 'template.html', 
     controller: 'Ctrl' 
     }) 
     .when('/route1', { 
     templateUrl: 'template.html', 
     controller: 'Ctrl' 
     }) 
     .when('/route2', { 
     templateUrl: 'template.html', 
     controller: 'Ctrl' 
     }) 
     .otherwise({ 
     // redirect to default url with latest params 
     redirectTo: myRouteProvider.default 
     }); 
    }) 

    .run(function(myRoute) { 
    // set default url (404) 
    myRoute.setDefault('/main'); 
    }) 

    .controller('Ctrl', function($scope, $location) { 
    $scope.$location = $location; 
    }); 

Где index.html содержит только

<div> 
    <a href="#/main">main</a><br> 
    <a href="#/route1">route1</a><br> 
    <a href="#/route2?param=abc">route2?param=abc</a><br> 
    <a href="#/404">otherwise</a><br> 
</div> 
<hr> 
<div ng-view></div> 

и маршруты template.html просто

<div> 
    path: {{ $location.path() }} 
    <br> 
    params: {{ $location.search() }} 
</div> 

Теперь, если вы переходите между ссылками и ударил othwerwise, вы будете redir до /main с любым params с предыдущего маршрута.

imgur


Связанная plunker здесь http://plnkr.co/edit/cqR2Nh

+0

Я принял другой ответ, поскольку он проще и наградил вас щедростью, как вы были первыми. Для меня тот факт, что нужно делать такие вещи, выглядит как угловая ошибка. – maaartinus

Смежные вопросы