2014-10-02 80 views
1

我很喜歡#signin路線,它會在任何頁面之前打開一個對話框。如何使用durandal路由器來激活對話框?

讓我們看看這個示例應用程序下面這樣的路線:

router.map([ 
    {route: '', moduleId: 'vm/home', title: "Home"}, 
    {route: 'about', moduleId: 'vm/about', title: "About"}, 
    {route: 'signin', moduleId: 'vm/signin', title: 'Sign In'} 
]); 

下面是使用範例:

  1. 用戶是#並導航到#signin:我們應該看到登錄對話頂部首頁頁面

  2. 用戶在#about並導航到#signin:我們應該看到登錄上的關於

  3. 用戶頂部對話框導航到http://localhost:9000/#signin:我們應該看到登錄對話框上的主頁頂部頁面

  4. 用戶在#signin並關閉對話框:我們應該看到對話框後面的頁面(後面總是有一個頁面)。

+0

[如何用DurandalJS創建「完整頁面對話框」的可能的重複](http://stackoverflow.com/questions/18537647/how-to-create-full-page-dialog-with-durandaljs) – 2014-10-03 09:51:28

+0

@Tambo ,它不是重複的,op正在尋找沒有路由的對話框,因爲我正在尋找一個解決方案,其中對話框就像是擁有自己路由的「頁面」。 – Dziamid 2014-10-03 13:18:57

回答

2

對話框和路由器都是插件,彼此之間沒有交互。

也有路由器顯示對話框將忽略路由器的工作原理 - 它有一個它轉儲內容的div。對話存在於所有這些之外。

但是,如果你想(我也可以這樣做),你可以試試這個。

dialog: true添加到路線圖。

重寫router.loadUrl方法。檢查路由是否是我們之前標記的對話路由,然後激活對話框。

我會讓對話框成爲子路線,這樣你就可以知道在對話框下面顯示哪個視圖。否則,你可能只需要顯示任何對話並忽略路由。

編輯:我不認爲這將完全工作。 loadUrl返回一個布爾值。您可以打開對話框並返回false以取消導航。

EDIT2:

我嘗試

loadUrl方法遍歷所有路線,每有一個回調,所以非常需要插入我們的邏輯到這個陣列。

for (var i = 0; i < handlers.length; i++) { 
    var current = handlers[i]; 
    if (current.routePattern.test(coreFragment)) { 
     current.callback(coreFragment, queryString); 
     return true; 
    } 
} 

將此數組添加到使用路由器route的方法中。 Durandal在映射路線時調用此方法,所以理想情況下我們可以在路線配置中添加一些額外的參數,並讓Durandal處理這些參數。但是configureRoute函數是路由模塊的內部函數,因此我們需要對其進行編輯,並確保在將來更新Durandal時複製更改。

我創建對話框路線的新列表:

{ route: 'taxcode/add(/:params)', moduleId: 'admin/taxcode/add', title: 'Add Tax Code', hash: '#taxcode/add', nav: false, dialog: true, owner: '#taxcodes' }, 
{ route: 'taxcode/edit/:id', moduleId: 'admin/taxcode/edit', title: 'Edit Tax Code', hash: '#taxcode/edit', nav: false, dialog: true, owner: '#taxcodes' } 

所有者的想法是,如果在最初的路線是這樣的一個情況下,我們需要對話背後的東西。

現在取代了configureRoute與此router.route電話:

router.route(config.routePattern, function (fragment, queryString) { 
    if (config.dialog) { 
     if (!router.activeInstruction()) { 
      // No current instruction, so load one to sit in the background (and go back to) 
      var loadBackDrop = function (hash) { 
       var backDropConfig = ko.utils.arrayFirst(router.routes, function (r) { 
        return r.hash == hash; 
       }); 
       if (!backDropConfig) { 
        return false; 
       } 
       history.navigate(backDropConfig.hash, { trigger: false, replace: true }); 
       history.navigate(fragment, { trigger: false, replace: false }); 
       queueInstruction({ 
        fragment: backDropConfig.hash, 
        queryString: "", 
        config: backDropConfig, 
        params: [], 
        queryParams: {} 
       }); 
       return true; 
      }; 

      if (typeof config.owner == 'string') { 
       if (!loadBackDrop(config.owner)) { 
        delete config.owner; 
       } 
      } 
      if (typeof config.owner != 'string') { 
       if (!loadBackDrop("")) { 
         router.navigate(""); 
         return; // failed 
       } 
      } 
     } 
     var navigatingAway = false; 
     var subscription = router.activeInstruction.subscribe(function (newValue) { 
      subscription.dispose(); 
      navigatingAway = true; 
      system.acquire(config.moduleId).then(function (dialogInstance) { 
       dialog.close(dialogInstance); 
      }); 
     }) 
     // Have a route. Go back to it after dialog 
     var paramInfo = createParams(config.routePattern, fragment, queryString); 
     paramInfo.params.unshift(config.moduleId); 
     dialog.show.apply(dialog, paramInfo.params) 
      .always(function() { 
       if (!navigatingAway) { 
        router.navigateBack(); 
       } 
      }); 
    } else { 
     var paramInfo = createParams(config.routePattern, fragment, queryString); 
     queueInstruction({ 
      fragment: fragment, 
      queryString: queryString, 
      config: config, 
      params: paramInfo.params, 
      queryParams: paramInfo.queryParams 
     }); 
    } 
}); 

確保導入dialog到模塊。

+0

我很想看到一個例子!我不清楚'loadUrl'中要重寫什麼,因爲它基本上只是匹配具有模式的路由。 – Dziamid 2014-10-08 11:59:25

+0

我會在某個時刻出發。我剛開始使用兒童路由器,因此對我來說也是非常新穎的! – Tim 2014-10-08 15:33:34

+0

另一種可能性是您可以掛接到許多路由器事件中的一個,例如'router:route:activating',並在那裏處理對話。 – Brett 2014-10-08 16:16:24

0

擴大我在評論中的建議,也許這樣的事情會起作用。只需在router:route:activating或其他類似事件之一上配置事件掛接,並攔截/#signin的激活。然後使用這個鉤子來顯示對話框。請注意,此示例僅用於說明目的。我在工作時無法提供一個工作示例。 :/我可以在回家時完成它,但至少這會給你一個想法。

router.on('router:route:activating').then(function (instance, instruction) { 
    // TODO: Inspect the instruction for the sign in route, then show the sign in 
    // dialog and cancel route navigation. 
}); 
+0

這似乎是一個優雅的解決方案。慢慢來一個例子。 – Dziamid 2014-10-09 19:02:35

1

那麼也許所有這一切都不需要使用您的家庭viewmodel的激活數據的技巧。 看看我創建的答案爲Github repo

這個想法是,路線接受一個可選的激活數據,您的家庭虛擬機的激活方法可能會檢查並相應地顯示所需的模式。

這種方式的好處是,您根本不需要觸摸現有的Durandal插件或核心代碼。 雖然我不確定這是否完全符合您的要求,因爲要求沒有詳細說明任何內容。

更新: 好吧我已經更新回購現在工作與泛化的額外要求。基本上現在我們利用殼內Durandal的Pub/Sub機制,或者將它放在任何你想要的地方。在那裏我們聽取路由器導航完成事件。發生這種情況時,請檢查指令集並搜索給定的關鍵字。如果是這樣,然後發射模態。通過使用導航完成事件,我們還確保主VM正確且完全加載。 對於那些想要導航到#signin的黑客,只需將它們手動重新路由到任何你想要的地方。

+0

回購+1,但有一點你錯過了。我真的希望這個對話框'在任何頁面之前打開'。您的解決方案將需要修復您可以登錄的所有潛在視圖模型。你能想出一個更廣泛的解決方案嗎? – Dziamid 2014-10-11 08:43:21

+0

我已更新到問題以更好地說明可能的用例,請看看! – Dziamid 2014-10-11 09:12:13

+0

好吧,我已經更新了我的帖子以及github回購 – zewa666 2014-10-11 11:56:49

相關問題