2016-06-07 11 views
4

我正在使用TypeScript自動填充組件(對於Angular 2,雖然這不是問題的核心),並且我希望通過可觀察對象來管理大部分(或全部) RxJs(5.0.0-beta.8)。在通過向上/向下箭頭鍵操作時,我在跟蹤當前項目位置方面存在問題:索引保持卡在0處。使用可觀察事件跟蹤前面列表中的當前位置

以下所有邏輯都被留在單獨的class中,該接收器接收輸入可觀察值併產生輸出觀察值以訂閱(這就是爲什麼不與Angular 2嚴格相關)。客戶端代碼訂閱正確輸出observables。

下面是一些代碼:

// Component responsible for managing only the list of suggestions 
// It receives inputs from text field and it produces outputs 
// as current index in list, when to hide list, etc. 
class AutocompleteListDriver { 
    currentIndex$: Observable<number>; 
    doClose$: Observable<void>; 
    // ... 

    constructor(... 
    matches$: Observable<string[]>, // list of suggestions matching text in field 
    keyUp$: Observable<KeyboardEvent>, // keyup events from text field 
    keyDown$: Observable<KeyboardEvent>, // keydown events from text field 
    ...) { 

    const safeMatches$ = matches$ 
     .startWith([]); // start with a clear, known state internally 

    // when list is empty, component is hidden at rest: 
    // detect keys only when component is visible 
    const isActive$ = safeMatches$ 
     .map(matches => matches.length !== 0); 

    const activeKeyUp$ = keyUp$ 
     .withLatestFrom(isActive$) 
     .filter(tuple => tuple[1]) // -> isActive 
     .map(tuple => tuple[0]); // -> keyboardEvent 

    this.currentIndex$ = safeMatches$ 
     .switchMap(matches => { 
     const length = matches.length; 
     console.log('length: ' + length); 

     const initialIndex = 0; 

     const arrowUpIndexChange$ = activeKeyUp$ 
      .filter(isArrowUpKey) 
      .map(_ => -1); 

     const arrowDownIndexChange$ = activeKeyUp$ 
      .filter(isArrowDownKey) 
      .map(_ => +1); 

     const arrowKeyIndexChange$ = Observable 
      .merge(arrowUpIndexChange$, arrowDownIndexChange$) 
      .do(value => console.log('arrow change: ' + value)); 

     const arrowKeyIndex$ = arrowKeyIndexChange$ 
      .scan((acc, change) => { 
      // always bound result between 0 and length - 1 
      const index = limitPositive(acc + change, length); 

      return index; 

      }, initialIndex) 
      .do(value => console.log('arrow key index: ' + value)) 
      .startWith(0); 

     return arrowKeyIndex$; 
     }) 
     .do(value => console.log('index: ' + value)) 
     .share(); 
    } 
} 

的想法是,每次的比賽(建議)的新名單發出,在列表當前指數應該開始新的「序列」,可以這麼說。每個序列從0開始,聽取由於向下/向上箭頭鍵的增加/減少,通過小心不超過下限/上限進行累加。

要開始新的序列我將其轉換爲switchMap。但是,隨着這樣的代碼,控制檯僅示出了:

length: 5 
index: 0 

和向上箭頭未檢測/向下鍵在所有(試戴arrowDownIndexChange$插入其它日誌),所以沒有更多的日誌和在最終部件沒有影響。這就好像他們的觀測數據不是已訂閱了,但據我所知switchMap應該訂閱最新生成的序列並從之前的所有序列中刪除/取消訂閱。

只是嘗試,我用mergeMap代替:在這種情況下,箭頭鍵被檢測到,但當然問題是所有的序列(由於之前的時刻匹配的情況下)合併在一起,它們的值彼此重疊。除此之外,無論如何,這些匹配列表將不時出現,因此總是存在一個點,即當前索引序列始終保持爲0.該序列與所有其他索引序列合併並重疊,從而導致索引的淨結果停留在0.

我在做什麼錯?

+0

無論如何,你可以把它變成一個plunkr?這將更容易追蹤這個問題。 – paulpdaniels

+0

該組件在其示例應用程序中已啓用[在github上](https://github.com/BrainCrumbz/ng2-autocomplete-words-example/)。 [這是](https://github.com/BrainCrumbz/ng2-autocomplete-words-example/blob/ec42b926f04abea6a722673a7389363196fa36a5/src/client/autocomplete/acw-list-driver.ts#L82)的'開關()'呼叫。我知道這不像一個笨蛋,但也許作爲第一步,可以幫助玩它? – superjos

回答

3

好的。顯然,我以前通過rxjs文檔發現錯誤(當然,我在寫下這個問題後得到了這個,然後尋找更多見解)。

看來switchMap不適合這種情況。我應該使用的是switch()。而這應該不會令人驚訝,來自.Net Reactive Extensions背景......但我不知道爲什麼語言之間的命名變化經常讓我誤會。

工作液應改爲:

this.currentIndex$ = safeMatches$ 
    // use map to generate an "observable of observables" 
    // (so called higher-order observable) 
    .map(matches => { 
    const length = matches.length; 
    // ... 
    }) 
    // "unwrap" higher order observable, by always 
    // keeping subscribed to the latest inner observable 
    .switch() 
    .do(value => console.log('index: ' + value)) 

編輯
這是不夠的。我也不得不放棄activeKeyUp$轉而生keyUp$

如果任何人有其他建議(或對當前行爲的解釋,例如activeKeyUp/keyUp),請隨時回答。

編輯#2
感謝@paulpdaniels評論:事實證明,真正的問題是,activeKeyUp$ Vs的keyUp$錯誤。用switchMap()代替map().switch()不會以任何方式損害功能。

+1

'switchMap()'是(應該)在語義上與'map()'+'switch()'相同。所以如果你在兩者之間得到不同的行爲,那可能是一個錯誤。 – paulpdaniels

+0

@paulpdaniels可以自由張貼消化作爲答案,所以我可以接受它。這是未來讀者的真正答案 – superjos

相關問題