Reputation: 2622
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:
IED Error Indication:
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;
})
);
})
}
}
Upvotes: 4
Views: 1488
Reputation: 56
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.
Upvotes: 1