OK、現在の安定版(@ 1.0.7)で動作するソリューションを見つけることができました。
この問題を処理する現在の方法には、$route 関連のイベントが含まれ、Angular と互換性のない URL をオンザフライで解析し、$http インターセプトと同様の方法で機能する追加のサービスを介してそれらを処理します。
ここで実際のコード例を見ることができます: http://embed.plnkr.co/fIA2xj/preview
主な手順
- いつものように角度互換性のないURLを渡します。site.com/url/ http://site.comにアクセスしてください
- $routeChangeStart イベントをリッスンし、で始まるパスの正しい URL パラメータを抽出します
/url/
- 正しい url パラメーターを角度互換の形式にエンコードします (この特定のケースでは、base64 を使用します)。angular は他の URL として扱われるため、encodeURIComponent を使用しないでください。
- ビジネスロジックを使用して別のルートにリダイレクトします。site.com/parsed-url/BASE64_GOES_HERE
- コントローラーで URL をデコードし、通常どおり使用します :)
コード
いつものようにangularアプリモジュールを作成する
angular.module('routes',[]).config([
'$routeProvider',
function($routeProvider){
$routeProvider
.when('/test', {templateUrl: 'test.html'})
// This one is important:
// We define a route that will be used internally and handle
// parameters with urls parsed by us via the URLInterceptor service
.when('/parsed-url/:url', {templateUrl: 'url.html', controller:'URLCtrl'})
.when('/', {redirectTo: '/test'})
.otherwise({templateUrl: '404.html'});
}
])
URL インターセプター サービス (シングルトン)
.service('URLInterceptor', function($rootScope, $location){
// We listen to $routeChangeStart event and intercept it if
// the path matches our url scheme. In this case, every route
// beginning with /url/ will be caught
$rootScope.$on('$routeChangeStart', function(e, next, current){
// $location.path does change BEFORE actual routing happens,
// so in this case we get parsed new location object
// for free.
// To be hones, a better way of handling this case might be using
// $locationChangeStart event instead, but it would require us to parse urls
// manually.
var path = $location.path();
// check if string begins with '/url/'
var matcher = path.slice(0,5);
var cleanPath = '';
if (matcher === '/url/'){
// Yes it does, yay!
// Remove leading '/url/' to extract the actual parameter
cleanPath = path.slice(5);
// Encode our url to a safe version. We know that encodeURIComponent won't
// work either, so a good choice might be base64.
// I'm using https://code.google.com/p/javascriptbase64/downloads
$location.path('/parsed-url/' + Base64.encode(cleanPath));
// Prevent default event execution. Note that, it won't cancel related $location Events
e.preventDefault();
}
});
return {
decode: Base64.decode,
encode: Base64.encode
}
})
コントローラー
// Main application controller
// We instantiate our URLInterceptor service here
.controller('AppCtrl',function($scope, $location, URLInterceptor){
$scope.navigateTo = function (path) {
$location.path('/url/' + path);
}
})
.controller('URLCtrl', function($scope, $routeParams, URLInterceptor){
$scope.url = URLInterceptor.decode($routeParams.url);
});
覚えておくべき 2 つのこと:
- できるだけクリーンなソリューションを作成しようとしましたが、通常、この方法でデータを angular に渡すことは良い習慣とは見なされないため、本当に必要でない限り使用しないようにしてください。
- この問題は、1 つのルートだけで処理できます。私はちょうどそれがこのようにきれいだと思います。