1

私はデュランダル アプリケーションを使用router.mapUnknownRoutesしており、URL が既知のルートに対応していない場合に、ユーザー フレンドリーなエラー ページを表示するために使用しています。これは問題なく動作します。たとえば/foo、 に移動し、それがルートと一致しない場合、 で指定されたモジュールmapUnknownRoutesが正しく表示されます。

ただし、パラメーター化されたルートがあり、パラメーターがバックエンドの何にも一致しない場合、同じエラー ページを表示する方法が見つかりません。

たとえばpeople/:slug、対応するモジュールのactivateメソッドが次のように見えるルートがあるとします。

this.activate = function (slug) {
    dataService.load(slug).then(function () {
        // ... set observables used by view ...
    });
};

たとえば に移動すると/people/foo、結果は、dataService.load('foo')データを返すかエラーを返すかによって異なります。

  • fooバックエンドに存在する場合は問題ありません。オブザーバブルが設定され、構成が続行されます。
  • fooが存在しない場合、エラーがスローされます ( がないため) catch。これにより、未処理のエラーが発生し、ナビゲーションがキャンセルされ、ルーターが機能しなくなります。

falseから戻ることができcanActivate、ルーターを中断することなく、よりクリーンな方法でナビゲーションがキャンセルされることを知っています. ただし、これは私が望んでいるものではありません。何か問題が発生したことをユーザーに伝えるために、無効な URL が必要です。

{ redirect: 'not-found' }から戻るか、似たようなことができることを知っていcanActivateます。ただし、これは戻るボタンを壊すため、ひどいものです。リダイレクトが発生した後、ユーザーが戻るを押す/people/fooと、別のエラーが発生し、別のリダイレクトが に戻りnot-foundます。

私はいくつかの異なるアプローチを試しましたが、主catchに promise 定義への呼び出しを追加することを含みます。

this.activate = function (slug) {
    dataService.load(slug).then(function () {
        // ... set observables used by view ...
    }).catch(function (err) {
        // ... do something to indicate the error ...
    });
};
  • activate(またはcanActivate) は、最初から一致しなかったかのように、ルートが実際には無効であることをルーターに通知 できますか?
  • URL を変更せずにルーターが別のモジュールを表示するように、 activate(または) は( ではなく) をcanActivate発行できますか?rewriteredirect
  • 現在のモジュールの代わりに他のモジュールを直接指定できますcomposeか (そして現在のモジュールの構成をキャンセルできますか)?

catchまた、エラーを飲み込む空のブ​​ロックも試しました(ここにトーストを追加して、ユーザーに通知することができます。これは、何もないよりはましです)。ただし、ビューで期待されるオブザーバブルが設定されないため、これにより多くのバインディング エラーが発生します。ビュー全体をバインドでラップしてエラーを防止できる可能性がありますifが、これにより、エラー メッセージではなく空白のページが表示されます。または、データの取得に失敗する可能性のあるすべてのビューにエラー メッセージを表示する必要があります。いずれにせよ、これはビューの汚染であり、DRY ではありません。なぜなら、「見つかりません」というエラー メッセージは 1 回だけ表示する必要があるからです。

無効な URL (具体的には、ルートに一致するが無効なパラメーター値を含む URL) が「ページが見つかりません」というページを表示するようにしたいだけです。これは他の人も望んでいることではないでしょうか?これを達成する方法はありますか?

4

2 に答える 2

2

ネイサンの答えは、完全に正しいとは言えませんが、私を正しい軌道に乗せたことがわかりました。私がやったことは少しハックに思えますが、うまくいきます。

router.navigate()-replaceとに渡すことができる 2 つのオプションがありますtrigger。渡すreplace(デフォルトは) は、と(またはハッシュ変更イベントを使用して同じものをシミュレートする)falseを使用して履歴プラグインを切り替えます。渡す(デフォルトは) は、実際にビューを読み込む (および URL を変更する) か、アドレス バーの URL のみを変更するかを切り替えます。これは私が望むもののように見えますが、間違っているだけです.URLを変更せずに別のビューをロードしたいのです.pushStatereplaceStatetriggertrue

(ドキュメントにはこれに関する情報がいくつかありますが、完全ではありません: http://durandaljs.com/documentation/Using-The-Router.html )

私の解決策は、not-foundモジュールに移動してアクティブ化し、アクティブ化をトリガーせずに元の URL に戻ることです。

したがって、データベース検索を行うモジュールでactivate、レコードが見つからない場合は次のように呼び出します。

router.navigate('not-found?realUrl=' + document.location.pathname + document.location.hash, { replace: true, trigger: true });

trigger: true冗長であることは認識していますが、明示的にしています)。

次に、not-foundモジュールには、activate次のような があります。

if (params.realUrl) {
    router.navigate(params.realUrl, { replace: true, trigger: false });
}

ユーザーに表示されるのは、モジュールがまだ表示されている間にリダイレクトされnot-found?realUrl=people/joe、すぐに URL が元に戻ることです。これらはどちらもスタイル ナビゲーションであるため、ユーザーが戻ると、壊れたリンクをクリックする前に表示されていたページ (つまり、戻るボタンの役割) に移動します。people/joenot-foundreplace

私が言ったように、これはハッキーに思えますし、URL のちらつきは好きではありませんが、私ができる最善のことのように思えます。ほとんどの人はアドレス バーに気付かないでしょう。

このソリューションを示す作業レポ

于 2015-10-07T15:18:16.287 に答える