Autocomplete with multiple selection (MdAutocompleteTrigger customization)
まだ誰も着手していません。
- 主要言語
- TypeScript
- スター
- 25k
- フォーク
- 6.8k
- 平均マージ
- 1日 8時間
- マージ済み PR(30日)
- 91
説明
#### Feature proposal:
It would be nice if `MdAutocomplete` and `MdAutocompleteTrigger` supported the `multiple` attribute similar to `MdSelect`, or at least configuration options that make creating your own easier.
#### What is the expected behavior?
It should be possible to create an Autocomplete with multiple selection.
#### What is the current behavior?
`MdAutocompleteTrigger` is coded to assume single selection and is not easily customized, which makes a custom multi-autocomplete difficult to develop. Currently, you must "monkey-patch" private methods in `MdAutocompleteTrigger`.
#### Which versions of Angular, Material, OS, TypeScript, browsers are affected?
> @angular/cli: 1.0.4
> node: 6.9.1
> os: linux x64
> @angular/common: 4.2.0
> @angular/material: 2.0.0-beta.6-f89c6db
> @angular/cli: 1.0.4
#### Is there anything else we should know?
Here are my notes on the major issues I encountered in developing my own multiple Autocomplete.
In `ngAfterContentInit`, I "monkey-patch" `MdAutocompleteTrigger`. You cannot extend `MdAutocompleteTrigger` because these methods are private.
The objective here is to:
1. not deselect other `MdOption`s on selection
2. leave the Autocomplete open after option selection event.
EDIT updated for beta12
```typescript
if (this.multiple) {
const self = this;
/*
easiest to just modify this MatAutoTrigger instance to get the behavior we want.
Hopefully, material2 will support this in the future
*/
const autoTrigger: any = this.mdAutoTrigger as any;
// make a no-op so other options aren't cleared when selecting an option
autoTrigger._clearPreviousSelectedOption = () => {};
// need to override to continue getting these events
// copied from material2/src/lib/autocomplete/autocomplete-trigger.ts with CHANGEs
autoTrigger._subscribeToClosingActions = function(this: any): Subscription {
const firstStable = first.call(this._zone.onStable.asObservable());
const optionChanges = RxChain.from(this.autocomplete.options.changes)
.call(doOperator, () => this._positionStrategy.recalculateLastPosition())
// Defer emitting to the stream until the next tick, because changing
// bindings in here will cause "changed after checked" errors.
.call(delay, 0)
.result();
// When the zone is stable initially, and when the option list changes...
return RxChain.from(merge(firstStable, optionChanges))
// create a new stream of panelClosingActions, replacing any previous streams
// that were created, and flatten it so our stream only emits closing events...
.call(switchMap, () => {
this._resetActiveItem();
this.autocomplete._setVisibility();
return this.panelClosingActions;
})
// when the first closing event occurs...
// CHANGE disable first() because we want to continue getting events
// .call(first)
// set the value, close the panel, and complete.
.subscribe(event => this._setValueAndClose(event));
};
// prevent closing on select option event
autoTrigger._setValueAndClose = function(this: any, event: MatOptionSelectionChange | null): void {
if (event && event.source) {
// CHANGE don't clear selection, clear input, or change focus
// this._clearPreviousSelectedOption(event.source);
// this._setTriggerValue(event.source.value);
this._onChange(event.source.value);
// this._element.nativeElement.focus();
this.autocomplete._emitSelectEvent(event.source);
}
// CHANGE added else clause (close non-MatOptionSelectionChange event)
else {
// NOTE this is the Subscription returned from _subscribeToClosingActions
// CHANGE unsubscribe from the Subscription created in _subscribeToClosingActions
this._closingActionsSubscription.unsubscribe();
this.closePanel();
// CHANGE clear input so placeholder can show selected values
self.clearInput();
}
};
}
```
Also, while working on this, I noticed that the code I was writing was very similar to `MdSelect` and most of the logic is in `MdAutocompleteTrigger`. So maybe what's needed is a new `MdMultiAutocompleteTrigger`, which uses the same `SelectionModel` system that `MdSelect` uses.
The one other issue is that even with `ngFor trackBy` sometimes `MdOption` instances lose their selected state. So every time the options are filtered, I double-check `MdOption.selected` and select() deselect() as necessary.
Also, the way `MdSelect` sets `MdOption.multiple` seems awkward, but I basically do the same thing as the `MdSelect` code.
FYI, my solution for displaying multiple values is just to clear the input, floatPlaceholder='never' and set placeholder to the `displayWith()` of each selected value separated by commas. This works fairly well. I also added a tooltip with the same content in case the entire text is not visible.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
まず MdAutocompleteTrigger と、対応する MdSelect の複数選択ロジックを読み、選択のクリア、閉じる操作、issue で説明されている private メソッドに注目してください。MdAutocomplete が複数選択をサポートするか、monkey-patching を使わずにサポートされたカスタマイズ方法を提供し、選択済みのオプションを保持したまま選択後もパネルを開いた状態にできれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- angular, typescript
- 領域
- frontend
- issue の種類
- 機能追加
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 25/100