4
votes

I have created a service to fetch search results. The function name is getSearchResults which is used to fetch the search results and I have a component from which I am subscribing to function 'getSearchResults. I also have an Observable called 'searchResults', I subscribe it to get the actual results in my component. I am getting subscribe not a function error when I subscribe to searchResults variable. Sometimes it works fine but when I hit the back button on the browser then it display the error.

Service:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import { Http, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
import { Router } from '@angular/router';

import { AppConfig } from '../app.config';

@Injectable()
export class SearchResultsService {

  // Observable string source
  private searchResultsSource = new BehaviorSubject<any>({"results": "null"});

  // Observable string stream
  searchResults: Observable<any>;

  constructor(
    private router: Router,
    private http: Http,
    private config: AppConfig) {

    this.searchResults = this.searchResultsSource.asObservable();

    }

  getSearchResults(query: string, field: string) {
    if(sessionStorage.getItem('searchResults')) {
      sessionStorage.removeItem('searchResults');
      console.log('removed');
    }

    else console.log('not removed');

    if (field == null || !field)
      field = '_all';

    if (query == null || !query)
      return;

    let token = JSON.parse(localStorage.getItem('authDetails')).accessToken;
    let headers = new Headers({ 'Authorization': token,
      'Access-Control-Allow-Origin': '*'});
    let params: URLSearchParams = new URLSearchParams();
    params.set('q', query);
    params.set('f', field);
    let options = new RequestOptions({ headers: headers,
      search: params
    });
    return this.http.get(this.config.apiUrl+'/search', options)
      .map((response: Response) => {
        console.log('response received');
        this.searchResults = response.json();
        sessionStorage.setItem('searchResults', JSON.stringify(this.searchResults));
        console.log((response.json()).results);
        this.emitSearchResults();
      },
      error => console.log(error));
  }

  emitSearchResults(): void {
    this.searchResultsSource.next(this.searchResults);
  }
}

Component:

import { Component, OnInit, OnDestroy, DoCheck } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import 'rxjs/add/operator/map';

import { SearchResultsService } from '../services/search-results.service';

@Component({
  moduleId: module.id,
  selector: 'app-search-results',
  templateUrl: './search-results.component.html',
  styleUrls: ['./search-results.component.css']
})
export class SearchResultsComponent implements DoCheck, OnInit {

  public searchResults;
  public searchResultsCount: number = 0;
  public subscription;
  public field: string;
  public query: string;

  constructor(
    private searchResultsService: SearchResultsService,
    private router: Router,
    private route: ActivatedRoute) { 

    console.log('on top');

    if(JSON.parse(sessionStorage.getItem('searchResults')))
      this.searchResults = JSON.parse(sessionStorage.getItem('searchResults'));

    this.searchResultsService.searchResults.subscribe(
      (results) => 
        this.searchResults = results);

    this.searchResults = this.searchResultsService.searchResults;

    this.field = this.route.snapshot.params['field'];
    this.query = this.route.snapshot.params['query'];

    console.log('in search results constructor');
    console.log(this.searchResults);
  }

  ngOnInit() {
    this.searchResultsService.getSearchResults(this.query, this.field).subscribe(
      (data) => {
        console.log('subs work');
      },
      (error) => {
        console.log('subs ot work');
      });
  }

  onClick() {
    this.subscription.unsubscribe();
    console.log('destroyed');
  }

  ngDoCheck() {
  }

}
3

3 Answers

2
votes

The problem was that I was using the same variable as an observable as well as for storing the search results. I made another variable to store search results and now the error is fixed.

0
votes

It probably has something to do with how you define subscription. Try this

import { Subscription } from 'rxjs/Rx';
...
public subscription: Subscription;
...

And then it should work just fine.

I also noticed that You are trying to subscribe to a method that does not exist. You only have emitSearchResults(): void and getSearchResults in your service.

I'd also define a variable as an observable not inside the constructor but inside a class like this

searchResults: Observable<any> = this.searchResultsSource.asObservable();
0
votes

@NitinSingh I don't have enough rep to add a comment, so I'll have to respond here.

The issue is in the mapping of the response from the http.get call. Don't do this.searchResults = response.json(); to set the value of this.searchResults. searchResults is observing searchResultsSource so instead you change the observed value by doing this.searchResultsSource.next(response) in the .map.

It will look like this

return this.http.get(this.config.apiUrl+'/search', options)
      .map((response: Response) => {
        searchResultssource.next(response)
      },
      error => console.log(error));

Also this.searchResults = this.searchResultsSource.asObservable();shouldn't be declared in the constructor.