Implementing Auto-Suggestions in loklak search

Auto-suggestions can add a friendly touch to the search engine. Loklak provides suggest.json API to give suggestions based on the previous search terms entered by the users. Moreover, suggest results needs to be reactive and quick enough to be displayed as soon as the user types a new character.

The main demand of the auto-suggestion feature was to make it really quick so as to make it look reactive.

I will explain how I implemented auto-suggestion feature and try to explain issues I faced and solution for that.

Ngrx Effects

The cycle for implementing auto-suggest goes like this:

The most important component in this cycle is effects as it is the event listener and it recognises the action immediately after it is dispatched and makes a call to loklak suggest.json API. We will look at how effects should look like for a reactive implementation of auto-suggestion. Making effects run effectively can make Rate Determining Step to be the API response time instead of any other component.

@Injectable()
export class SuggestEffects {@Effect()
suggest$: Observable<Action>
= this.actions$
.ofType(suggestAction.ActionTypes.SUGGEST_QUERY)
.debounceTime(300)
.map((action: suggestAction.SuggestAction) => action.payload)
.switchMap(query => {
const nextSuggest$ = this.actions$.ofType(suggestAction.ActionTypes.SUGGEST_QUERY).skip(1);return this.suggestService.fetchQuery(query)
.takeUntil(nextSuggest$)
.map(response => {
return new suggestAction.SuggestCompleteSuccessAction(response);
})
.catch(() => of(new suggestAction.SuggestCompleteFailAction()));
});constructor(
private actions$: Actions,
private suggestService: SuggestService,
) { }}

 

This effect basically listens to the action  SUGGEST_QUERY and recognises the action, next it makes a call to the Suggestion service which receives data from the server. Now, as the data is received, it maps the response and passes the response to the SuggestCompleteSuccessAction so that it could change the considered state properties. The debounce time is kept low (equal to 300) so as to detect next SUGGEST_QUERY within next 300ms of the API suggest.json call. This will help to whole cycle of suggest response reactive and help in early detection of the action.

Angular Components

In this component, I will explain what changes I made to the feed header component for autocomplete to run effectively.

@Component({
selector: ‘feed-header-component’,
templateUrl: ‘./feed-header.component.html’,
styleUrls: [‘./feed-header.component.scss’],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FeedHeaderComponent {
public suggestQuery$: Observable<Query>;
public isSuggestLoading$: Observable<boolean>;
public suggestResponse$: Observable<SuggestResults[]>;
public searchInputControl = new FormControl();
constructor(
private store: Store<fromRoot.State>,
) { }ngOnInit() {
this.getDataFromStore();
this.setupSearchField();
}private getDataFromStore(): void {
this.suggestQuery$ = this.store.select(fromRoot.getSuggestQuery);
this.isSuggestLoading$ = this.store.select(fromRoot.getSuggestLoading);
this.suggestResponse$ = this.store.select(fromRoot.getSuggestResponseEntities);
}private setupSearchField(): void {
this.__subscriptions__.push(
this.searchInputControl
.valueChanges
.subscribe(query => {
this.store.dispatch(new suggestAction.SuggestAction(value));
})

);
}
}

 

We have created a FormControl searchInputControl which would keep a check on the input value of the search box and would dispatch an action SuggestAction() as soon as its value changes. Next, we have to subscribe to the observables of suggestion entities from the store as in the function “this.getDataFromStore()”.The data is received from the store and now we can proceed with displaying suggestion data in the template.

Template

HTML language has an tag datalist which can be used to display auto-suggestion in the template but datalist shows less compatibility with the Angular application and makes rendering HTML slow with next suggestion based on the some different history of the query.

Therefore, we can use either Angular Material’s md-autocomplete or create an auto-suggestion box to display suggestions from scratch (this would add an advantage of customising CSS/TS code). md-autocomplete would add an advantage with of this element being compatible with the Angular application so in loklak search, we would prefer that.

<input mdInput required search autocomplete=“off” type=“text” id=“search” [formControl]=“searchInputControl” [mdAutocomplete]=“searchSuggestBox”
(keyup.enter)=“relocateEvent.emit(query)” [(ngModel)]=“query”/><mdautocomplete #searchSuggestBox=”mdAutocomplete”><mdoption *ngFor=“let suggestion of (suggestResponse$ | async).slice(0, 4)” [value]=“(suggestQuery$ | async)”>{{suggestion.query}}</mdoption>

</mdautocomplete>

 

In the input element, we added an attribute [mdAutocomplete]=”searchSuggestBox” which links md-autocomplete to the input box #searchSuggestBox=”mdAutocomplete”. This makes auto suggestion box attached to the input.

Now, the chain is created with user input being the source of action and display of auto-suggestion data being the reaction.

References: