0

I have a couple of components that contain mat-autocomplete inputs where the data is pulled from a service.

The site itself is also translated into 3 different languages using @ngx-translate/core.

The autocompletes in the database have the associated language code sent across with the API call so I get the right data, so when the site loads for example it will call /api/categories/en for example to get the english categories available.

How can I refresh this list when the user switches languages please? for example if they switch to french I need to trigger a refresh?

The code for my language toggle dropdown is a follows;

component.html;

<div class="dropdown">
        <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            Select Language
        </button>
        <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
            <a class="dropdown-item" (click)="switchLanguage('pt')"><span class="flag-icon flag-icon-gr"></span> Portugese</a>
            <a class="dropdown-item" (click)="switchLanguage('en')"><span class="flag-icon flag-icon-gr"></span> English</a>
            <a class="dropdown-item" (click)="switchLanguage('fr')"><span class="flag-icon flag-icon-gr"></span> French</a>
        </div>
    </div>

where the component.ts is;

import { Injectable, Inject, Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
    selector: 'nav-menu',
    templateUrl: './navmenu.component.html',
    styleUrls: ['./navmenu.component.css']
})
export class NavMenuComponent {
    public isCollapsed = true;
    public status = false;

    constructor(private translate: TranslateService) {

    }

    public switchLanguage(language: string) {
        this.translate.use(language);
    }
}

and the app.component.ts I initially set the language as;

import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
    selector: 'app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    constructor(private translate: TranslateService) {
        translate.addLangs(["en", "pt", "fr"]);
        translate.setDefaultLang('pt');

        let browserLang = translate.getBrowserLang();
        translate.use(browserLang.match(/en|pt|fr/) ? browserLang : 'en');
    }

}

My mat-automplete .ts lookup code is;

ngOnInit() {

        this.categorySubscription = this.service.getCategories().subscribe((categories: ICategory[]) => {

            this.options = categories;

            this.filteredOptions = this.searchForm.get('trade').valueChanges
                .pipe(
                startWith(''),
                map(options => options ? this.filter(options) : this.options.slice())
                );
        });

....

Where the GetCategories Service function is;

getCategories(): Observable<ICategory[]> {

        let headers = new Headers({
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': environment.apiUrl
        });

        let options = new RequestOptions({ headers: headers });

        return this.http.get(environment.apiUrl + "/api/trade/category/" + this.currentLanguage, options)
            .map(res => res.json())
            .catch(this.handleError);
    }

So really all I need to do I think is detect when the language changes and trigger a refresh? Could anyone advise on how I would do this please?

Matthew Flynn
  • 3,661
  • 7
  • 40
  • 98
  • Well, you know when the language changes, is when `switchLanguage()` gets called. What's the relationship between the navmenu and the autocomplete components? – bugs Apr 06 '18 at 08:11

1 Answers1

3

EventEmitter should do the trick. Basically, you need to subscribe to the language change event. Inside your switchLanguage method you could call a service method changeLanguage that emits a signal to its subscribers:

@Injectable()
export class TranslateService {
    public languageChanged: EventEmitter<any> = new EventEmitter();

    changeLanguage(language) {
        this.languageChanged.emit(language)
    }
}

You can subscribe to that change in the components you want to immediately react to the change, just type in your component constructor:

this.langSubscription= this.languageService.changeLanguage.subscribe(lang=> this.refreshAutocompleteItems(lang))

Don't forget to unsubscribe in the ngOnDestroy method of the component

 ngOnDestroy() {
    this.langSubscription.unsubscribe()
 }
  • looks good I'll begin implementing it, quick question `TranslateService` is currently imported as a part of `@ngx-translate/core` will this need to be named differently for the constructor injection? or if i include both will it add these on as extension methods? – Matthew Flynn Apr 06 '18 at 10:12
  • I think it can cause homonymy. I haven't used `@ngx-translate/core` so I didn't know a `Translate Service` already existed – Michele Sapignoli Apr 06 '18 at 10:17
  • 1
    I had a few issues with doing this and then found this link that recommended not using `EventEmitter` as it was an anti pattern, https://stackoverflow.com/questions/34376854/delegation-eventemitter-or-observable-in-angular/35568924#35568924 – Matthew Flynn Apr 06 '18 at 11:21
  • Not sure what you think of this? – Matthew Flynn Apr 06 '18 at 11:21
  • Subjects are a powerful mean. Honestly, I do not have so much experience on that. I thought of an EventEmitter because maybe it's a bit simpler and more immediate but it seems the best solutions is the one you just linked.. and not so hard to implement too – Michele Sapignoli Apr 06 '18 at 11:29