4

I have an Observable stream that obviously outputs an array into the subscribe block. I am trying to assign the response to an array variable to render the autocompletion results. Everything works fine except for the typescript error.

Autocomplete Component:

@Component({
  selector: 'auto-complete',
  styleUrls: ['auto-complete.component.scss'],
  template: `
    <div class="ac-container">
      <div class="ac-input">
        <input type="text" [(ngModel)]="query" (keyup)="filter()">
      </div>
      <div class="ac-results" *ngIf="results.length > 0">
        <ul *ngFor="let item of results">
          <li>
            <a (click)="select(item)">{{item}}</a>
          </li>
        </ul>
      </div>
    </div>
  `
})

export class AutoCompleteComponent {
  @Input() fn: Function;

  public query = '';
  public results = [];

  filter() {
    let value = Observable
      .from(this.query)
      .throttleTime(20)
      .map(value => value)
      .distinctUntilChanged()
      .map(search => this.fn(search))
      .switch()
      .subscribe(response => {
        this.results = response;
      }, error => {}
    );
  }
}

Parent Component:

@Component({
  selector: 'auto-completor',
  template: `<auto-complete [fn]="apiSearch"></auto-complete>`
})

export class AppComponent implements OnInit {
  public results: any;

  constructor(
    private service: AppService
  ) {}

  public apiSearch(term) {
    return this.service.getSearchData(term);
  }

  ngOnInit() {
    this.apiSearch = this.apiSearch.bind(this);
  }
}

Error:

enter image description here

IED Error Indication:

enter image description here

I wish I could show examples of things I tried but all I did was googled. I have no idea. Thanks.

Edit / Additions

Fake DB/Http Response

import { Injectable } from '@angular/core';

@Injectable()
export class Database {
  private FAILURE_COEFF = 10;
  private MAX_SERVER_LATENCY = 200;

  private getRandomBool(n) {
    var maxRandomCoeff = 1000;
    if (n > maxRandomCoeff) n = maxRandomCoeff;
    return Math.floor(Math.random() * maxRandomCoeff) % n === 0;
  }

  public getSuggestions(text) {
    var pre = 'pre';
    var post = 'post';
    var results = [];
    if (this.getRandomBool(2)) {
      results.push(pre + text);
    }
    if (this.getRandomBool(2)) {
      results.push(text);
    }
    if (this.getRandomBool(2)) {
      results.push(text + post);
    }
    if (this.getRandomBool(2)) {
      results.push(pre + text + post);
    }

    return new Promise((resolve, reject) => {
      var randomTimeout = Math.random() * this.MAX_SERVER_LATENCY;
      setTimeout(() => {
        if (this.getRandomBool(this.FAILURE_COEFF)) {
          reject();
        } else {
          resolve(results);
        }
      }, randomTimeout);
    });
  }
}

App Service Converting the promise response to Observable

export class AppService {

  constructor(
    private database: Database
  ) {}

  public getSearchData(term) {
    return Observable.defer(() => {
      return Observable.fromPromise(this.database.getSuggestions(term)
        .then(function(res) {
          return res;
        })
      );
    })
  }
}
8
  • How is the search actually being done? Are you using HttpClient? Commented Dec 20, 2017 at 18:01
  • I edited the post to answer your question. I basically have a fake database response that responds with a promise and I wrap the promise with an observable in my service. Commented Dec 20, 2017 at 18:08
  • What about database.getSuggestions? Commented Dec 20, 2017 at 18:13
  • database.getSuggestions is calling the public method in the fake db. Commented Dec 20, 2017 at 18:17
  • 1
    The following worked. public results: any = []; Thanks. Commented Dec 20, 2017 at 18:23

1 Answer 1

1

The problem is that the Observable is not typed, because your function fn has no call signature. I cannot check it at the moment, but if you would give fn a lambda expression call signature, the observable will probably take over it's types, enabling you to assign it to results.

@Input() fn: (string) => string[];

Alternatively, you could type results as any, but that's just a quick and very dirty workaround to remove types altogether.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.