Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm writing a real-time search functionality in Angular with RxJS. I'm getting some error as TypeError: Cannot read property 'pipe' of undefined. I'm using Angular 7 and I have tried different code samples from StackOverfloew, but couldn't fix this issue.

app.Component.html

<input type='text' class="form-control input-txt-start" placeholder="Search Domain Name" name="domainId" (keyup)='getSearchResults(searchTerm$.next($event.target.value))'>
<ul *ngIf="results">
    <li *ngFor="let result of results | slice:0:9">
        {{ result}}
<p *ngIf="error">
    {{error}}

app.component.ts

import { Component, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators, NgForm, FormControl } from '@angular/forms';
import { SearchService } from 'src/app/services/search.service';
import { Subject } from 'rxjs';
@Component({
  providers: [SearchService]
export class AppComponent implements OnInit { 
  results: Object;
  searchTerm$: any = new Subject();
  error: any;
  constructor(private searchService: SearchService) { }
  ngOnit() { }
  getSearchResults(search) {
    this.searchService.search(search).subscribe((res) => {
      console.log(res);
      this.results = res;
    }, err => {
      console.log(err);
      this.error = err.message;

search.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { distinctUntilChanged } from 'rxjs/operators';
import { map } from 'rxjs/operators';
import { switchMap } from 'rxjs/operators';
import { environment } from '../../environments/environment';
@Injectable({
  providedIn: 'root'
export class SearchService {
  public httpOptions = {
    headers: new HttpHeaders({'Content-Type': 'application/json'})
  baseUrl: String = `${environment.API_URL}/api/domainCharts`;
  queryUrl: String = '?search=';
  constructor( private http: HttpClient ) { }
  search(terms: Observable<string>) {
    return terms.pipe(debounceTime(500)).pipe(distinctUntilChanged()).pipe(switchMap(term => this.searchEntries(term)));
  searchEntries(term) {
    return this.http.get(`${this.baseUrl}${this.queryUrl}${term}`);
                I have changed it to return terms.pipe(debounceTime(500), distinctUntilChanged(), switchMap(term => this.searchEntries(term))); but I'm still getting TypeError: Cannot read property 'pipe' of undefined
– Ram
                Jun 10, 2019 at 12:02

There are more than 1 thing that are not right with what you are asking.

First, you are passing a Subject and expecting an Observable. This is why you are getting error

TypeError: Cannot read property 'pipe' of undefined

Then, you are passing Subject as term (I assume you want to send search keyword).

You don't need a Subject in your situation. You can do it like this:

Template:

<input type='text' class="form-control input-txt-start" placeholder="Search Domain Name" name="domainId" (keyup)='getSearchResults($event)'>  <---- Send only $event here

Component:

getSearchResults(event) {
    this.searchService.search(event.target.value).subscribe((res) => { // <--- Get target value of event
      console.log(res);
      this.results = res;
    }, err => {
      console.log(err);
      this.error = err.message;

Service:

search(term) {  // <--- Notice that the parameter name became term instead of terms
    // You can use of() method of RxJS
    // You need to import of with "import { of } from 'rxjs';"
    // You can chain you operators in pipe() method with commas
    return of(term).pipe(
       debounceTime(500),
       distinctUntilChanged(),
       switchMap(() => this.searchEntries(term) // <--- Notice that, this function has no parameter
                When I changed as per your suggestion as below,   ` search(term) {          return terms.pipe(debounceTime(500), distinctUntilChanged(), switchMap(() => this.searchEntries(term)));   } `  1. In return statement, if it is terms, it says Cannot find name 'terms' 2. In return statement, if I change it to term, it says TypeError: term.pipe is not a function
– Ram
                Jun 10, 2019 at 12:25
                Updated the answer. You could use of() method of RxJS: learnrxjs.io/operators/creation/of.html
– Harun Yilmaz
                Jun 10, 2019 at 12:31
                But this way, distinctUntilChanged() becomes meaningless as you create a new observable every time this function is fired. I think you need to move debounce and distinctUntilChanged to component file. Maybe you can use fromEvent of RxJS to achieve this: learnrxjs.io/operators/creation/fromevent.html
– Harun Yilmaz
                Jun 10, 2019 at 12:38
                Thanks a ton @Harun, it worked for me. I will try by moving debounce and distinctUntilChanged and using fromEvent of RxJS and let you know.
– Ram
                Jun 11, 2019 at 4:13
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.