APIから生徒を検索するAngularアプリを作成します。正常に機能しますが、入力値が変更されるたびにAPIを呼び出します。私はデバウンスと呼ばれるものが必要であるという調査を行いましたが、これをアプリに実装する方法がわかりません。
App.component.html
<div class="container">
<h1 class="mt-5 mb-5 text-center">Student</h1>
<div class="form-group">
<input class="form-control form-control-lg" type="text" [(ngModel)]=q (keyup)=search() placeholder="Search student by id or firstname or lastname">
</div>
<hr>
<table class="table table-striped mt-5">
<thead class="thead-dark">
<tr>
<th scope="col" class="text-center" style="width: 10%;">ID</th>
<th scope="col" class="text-center" style="width: 30%;">Name</th>
<th scope="col" style="width: 30%;">E-mail</th>
<th scope="col" style="width: 30%;">Phone</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let result of results">
<th scope="row">{{result.stu_id}}</th>
<td>{{result.stu_fname}} {{result.stu_lname}}</td>
<td>{{result.stu_email}}</td>
<td>{{result.stu_phonenumber}}</td>
</tr>
</tbody>
</table>
</div>
App.component.ts
import { Component} from '@angular/core';
import { Http,Response } from '@angular/http';
import { Subject, Observable } from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
results;
q = '';
constructor(private http:Http) {
}
search() {
this.http.get("https://www.example.com/search/?q="+this.q)
.subscribe(
(res:Response) => {
const studentResult = res.json();
console.log(studentResult);
if(studentResult.success) {
this.results = studentResult.data;
} else {
this.results = [];
}
}
)
}
}
私はこのようなことを試みましたが、エラーですプロパティdebounceTimeはSubject <{}>タイプには存在しません
mySubject = new Subject();
constructor(private http:Http) {
this.mySubject
.debounceTime(5000)
.subscribe(val => {
//do what you want
});
}
これも機能しません。 プロパティ「fromEvent」はタイプ「typeof Observable」に存在しません
Observable.fromEvent<KeyboardEvent>(this.getNativeElement(this.term), 'keyup')
それで、これを実装する正しい方法は何ですか?
ありがとうございました。
コンポーネントでは、このようなことを行うことができます。 RxJS Subject
を作成します。search
イベントで呼び出されるkeyup
メソッドで、作成したこのSubject
で.next()
を実行します。次に、ngOnInit()
のsubscribe
は、以下のコードのように、1秒間debounce
になります。
searchTextChanged = new Subject<string>();
constructor(private http:Http) {
}
ngOnInit(): void {
this.subscription = this.searchTextChanged
.debounceTime(1000)
.distinctUntilChanged()
.mergeMap(search => this.getValues())
.subscribe(() => { });
}
getValues() {
return this.http.get("https://www.example.com/search/?q="+this.q)
.map(
(res:Response) => {
const studentResult = res.json();
console.log(studentResult);
if(studentResult.success) {
this.results = studentResult.data;
} else {
this.results = [];
}
}
)
}
search($event) {
this.searchTextChanged.next($event.target.value);
}
rxjs v6には、オペレーターのインポートポイントの簡素化など、いくつかの重大な変更があります。 rxjs-compat
をインストールしてみてください。コードが移行されるまで、これらのインポートパスが追加されます。
RxJS
から必要な演算子をインポートします。以下はRxJS 5.x用です
import { Subject } from "rxjs/Subject";
import "rxjs/add/operator/debounceTime";
import "rxjs/add/operator/distinctUntilChanged";
import { Observable } from "rxjs/Observable";
import "rxjs/add/operator/mergeMap";
angular(およびrxjs)の新しいバージョンでこれに遭遇した人のために。
新しいRxjsにはパイプ可能な演算子があり、このように使用できます(受け入れられた回答コードから)
ngOnInit() {
this.subscription = this.searchTextChanged.pipe(
debounceTime(1000),
distinctUntilChanged(),
mergeMap(search => this.getValues())
).subscribe((res) => {
console.log(res);
});
angular 6およびrxjs 6を使用している場合、これを試してください:subscribe
の前の.pipe(debounceTime(1000))
に注意してください
import { debounceTime } from 'rxjs/operators';
search() {
this.http.get("https://www.example.com/search/?q="+this.q)
.pipe(debounceTime(1000))
.subscribe(
(res:Response) => {
const studentResult = res.json();
console.log(studentResult);
if(studentResult.success) {
this.results = studentResult.data;
} else {
this.results = [];
}
}
)
}
また、angular formControlsを使用して、入力検索フィールドをバインドできます。
<input class="form-control form-control-lg"
type="text" [formControl]="searchField"
placeholder="Search student by id or firstname or lastname">
app.component.tsファイル内の検索フィールドの変更に反応するには、searchFieldでvalueChanges observableを使用します。
searchField: FormControl;
ngOnInit() {
this.searchField.valueChanges
.debounceTime(5000)
.subscribe(term => {
// call your service endpoint.
});
}
オプションでdistinctUntilChangedを使用できます(公開されている値が前の値と異なる場合にのみ、出力ストリームに公開されます)
searchField: FormControl;
ngOnInit() {
this.searchField.valueChanges
.debounceTime(5000)
.distinctUntilChanged()
.subscribe(term => {
// call your service endpoint.
});
}
デモ リンク
チュートリアルソース リンク
テンプレート変数の使用
<input type="text" #movieSearchInput class="form-control" placeholder="Type any movie name" />
...
...
fromEvent(this.movieSearchInput.nativeElement, 'keyup').pipe(
// get value
map((event: any) => {
return event.target.value;
})
// if character length greater then 2
,filter(res => res.length > 2)
// Time in milliseconds between key events
,debounceTime(1000)
// If previous query is diffent from current
,distinctUntilChanged()
// subscription for response
).subscribe((text: string) => {
this.isSearching = true;
this.searchGetCall(text).subscribe((res)=>{
console.log('res',res);
this.isSearching = false;
this.apiResponse = res;
},(err)=>{
this.isSearching = false;
console.log('error',err);
});
});
...
...
user.component.html
<input type="text" #userNameRef class="form-control" name="userName" > <!-- template-driven -->
<form [formGroup]="regiForm">
email: <input formControlName="emailId"> <!-- formControl -->
</form>
user.component.ts
import { fromEvent } from 'rxjs';
import { switchMap,debounceTime, map } from 'rxjs/operators';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
constructor(private userService : UserService) { }
@ViewChild('userNameRef') userNameRef : ElementRef;
emailId = new FormControl();
regiForm: FormGroup = this.formBuilder.group({
emailId: this.bookId
});
ngOnInit() {
fromEvent(this.userNameRef.nativeElement,"keyup").pipe(
debounceTime(3000),
map((userName : any) =>userName.target.value )
).subscribe(res =>{
console.log("User Name is :"+ res);
} );
//--------------For HTTP Call------------------
fromEvent(this.userNameRef.nativeElement,"keyup").pipe(
debounceTime(3000),
switchMap((userName : any) =>{
return this.userService.search(userName.target.value)
})
).subscribe(res =>{
console.log("User Name is :"+ res);
} );
----------
// For formControl
this.emailId.valueChanges.pipe(
debounceTime(3000),
switchMap(emailid => {
console.log(emailid);
return this.userService.search(emailid);
})
).subscribe(res => {
console.log(res);
});
}
*注意:入力要素がngIfブロックに存在しないことを確認してください。