1
votes

I'm having trouble wrapping my head around implementing an Observable clicking event to a function I already implemented. The examples I have seen so far are implemented using the fromEvent or Subject like so;

import {Subject} from "rxjs/Subject";

export class Component {

    private clickStream$ = new Subject<Event>();

    @Output() observable$ = this.clickStream.asObservable();

    buttonClick(event:Event) {
        this.clickStream$.next(event);
    }
}

their html

<button type="button" (click)="buttonClick($event)">click me</button>

Now consider my implementation below.

component.ts

export class MyComponent {
  result;
  public search(queryString: string) {
    this.myService.search().subscribe((res) => result = res )
  }
}

index.html

<form [formGroup]="searchForm">
    <input
      formControlName="queryString"
      placeholder="Enter keyword"
      type="text"
      (keyup.enter)="search(searchForm.value.queryString)"
     >
     <div (click)="search(searchForm.value.queryString)"></div> <!-- added an icon with css ->
</form>

service.ts

export class SearchService {
constructor(private http: HttpClient) {}

  search(queryString: string) {
    if (!queryString) {
      return;
    }
    return this.http.get(`${this.BASE_URL}&q=${queryString}`);
  }

}

My trouble is how to use my current search() and still be able to subscribe to my myService.search() method while using the approach I found. (i.e. the example code in this post) I understand ( I think ) streams, and the concept of Observables, but yet this is kicking my butt.

thanks in advance for any help.

1
1. You need to use the correct method name. onSearch is not the same name as search and should throw en exception. 2. you can't return anything useful from subscribe. You can make an assignment but return res is useless. If you wanted to see the latest value you could create a field in your component and assign to that ore use an async pipe and return an observable from the method (or assign the resulting observable to a field in your component.). 3. Your component method search receives an input but you do nothing with that in your service call, why? - Igor
The @Output() usage looks wrong. Here is @Output explained angular.io/guide/template-syntax#how-to-use-output - sneas
@Igor sorry I was trying to simply my example here from my original code, so that I'd hide some stuff that doesn't matter afterall. I've updated my examples - Diego
@sneas Do you have a working implementation for using Observables and clicking events in what i'm trying to accomplish? - Diego

1 Answers

2
votes

There are some fundemental issues with your code.

1) There are a few typos, namely the methods such as your service method (search or searchMedPolicies?)

2) You did not import and initialise your formGroup within your component.

3) The way you handle your subscriptions on your component - there is no need to add the return statement on your subscription.

As for your subscription event, you can simply feed the click event to your Subject using next().

Then, you subscribe to your clickStream$ Subject and make the necessary HTTP requests.

Here are my recommended corrections.

<form [formGroup]="searchForm">
  <input
    formControlName="queryString"
    placeholder="Enter keyword"
    type="text"
    (keyup.enter)="onSearch()"
   >
   <div (click)="onSearch($event)"></div> 
</form>

And on your component.ts,

import { Component, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { Subject } from 'rxjs';
import { switchMap } from 'rxjs/operators';

// other imports 

@Component({
  // etc etc
})

export class YourComponent implements OnInit {
  clickStream$ = new Subject<Event>();

  searchForm = this.fb.group({
    queryString: '',
  })

  constructor(
    private fb: FormBuilder, 
    private myService: SearchService,
  ) { }

  ngOnInit() {
    this.clickStream$
      .pipe(
        switchMap((event) => {            
          const { queryString } = this.searchForm.value;
          // console.log(event);
          // console.log(queryString);

          return this.myService.search(queryString)
        }),
      ).subscribe(response => {
        console.log(response);
        // do the rest
      });
  }

  onSearch() {
    this.clickStream$.next(event);
  }
}

And on your service.ts, make sure the method names are matching too.

export class SearchService {

  constructor(private http: HttpClient) {}

  search(queryString: string) {
    if (!queryString) {
      return;
    }
    return this.http.get(`${this.BASE_URL}&q=${queryString}`);
  }

}