#javascript #angular #typescript #rxjs #ngx-translate
#javascript #angular #typescript #rxjs #ngx-перевести
Вопрос:
Я использую директиву [displayWith] в моем mat-автозаполнении. Он отлично работает, когда я вручную выбираю значения, но когда я перезагружаю страницу, я не получаю перевод. Параметр, необходимый для перевода, асинхронно загружается из параметров запроса в ngOnInit. Поэтому я полагаюсь на параметр async, но моя displayFunction () — это функция синхронизации. Как это решить?
Без функции [displayWith] все работает нормально, но без перевода (это просто отображение чистых значений, чего я не хочу). Поэтому я уверен, что остальная часть кода правильная.
Мой mat-автозаполнение:
<mat-form-field [formGroup]="cityForm"
appearance="outline"
floatLabel="never"
color="primary">
<mat-icon matPrefix>location_on</mat-icon>
<input type="text" placeholder="{{ 'job_offer_search_bar.job-offer-search-bar-city-form.placeholder' | translate }}"
aria-label="Number" matInput
formControlName="cityControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="onSelectionChanged($event.option.value)"
[displayWith]="displayFn.bind(this)">
<mat-option>
{{ 'job_offer_search_bar.job-offer-search-bar-city-form.all' | translate }}
</mat-option>
<mat-option *ngFor="let city of filtredCities | async" [value]="city">
{{ 'job_offer_search_bar.job-offer-search-bar-city-form.city' | translate:"{ city: '" city "' }"}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
Моя функция displayWith приведена ниже:
displayFn(val: string){
if (!val) return '';
let stringToReturn;
this.translate.get('job_offer_search_bar.job-offer-search-bar-city-form.city', {city: val}).subscribe(value => {
console.log('inside subscribe', value);
stringToReturn = value;
});
console.log('after sub', stringToReturn);
if (stringToReturn != undefined) {
return stringToReturn;
} else {
return 'Sorry, value has not been translated';
}
Console.log in subscribe
вызывается после console.log after subscribe
. Итак, подписка выполняется после того, как я получу свой параметр для перевода, то есть после моего возвращения…
Мне нужен какой-нибудь трюк или подсказка, чтобы передать мою переведенную строку в качестве возврата.
Я предполагаю, что есть способ сделать это. Любая помощь будет принята с благодарностью.
Ответ №1:
Наблюдаемые объекты в большинстве случаев являются асинхронными функциями. В зависимости от вашей реализации вы можете использовать translate.instant
displayFn(val: string) {
const defaultMessage = 'Sorry, value has not been translated';
return val
? this.translate.instant('job_offer_search_bar.job-offer-search-bar-city-form.city', { city: val }) || defaultMessage
: '';
}
Если функция instant вызывается до загрузки файла перевода, она вернет значение undefined.
Редактировать:
displayFn(val: string) {
const translate$ = this.translate.get('job_offer_search_bar.job-offer-search-bar-city-form.city', { city: val }).pipe(
map(translatedText => translatedText || 'Sorry, value has not been translated')
)
return val
? translate$
: of('');
}
[displayWith]="displayFn.bind(this) | async"
Комментарии:
1. Я использовал
translate.instant
, но, как я уже сказал, мне нужен параметр для перевода, который загружается асинхронно: (Поэтомуtranslate.instant
он давал мне только идентификатор перевода… В этом случаеjob_offer_search_bar.job-offer-search-bar-city-form.city
2. И ваше решение возвращает мне пустую строку ‘ ‘
3. Попробуйте этот новый код, который я опубликовал. Имейте в виду, что использовать канал асинхронно с функциями нецелесообразно ни для привязки функций к свойствам вообще.
4. К сожалению, сейчас я получаю 2 ошибки в консоли: Ошибка: InvalidPipeArgument: ‘функция () { [машинный код] }’ для канала ‘AsyncPipe’ и ошибка типа: не удается прочитать свойство ‘dispose’, равное нулю. Но все компилируется нормально
5. Понятно, извините, у меня заканчиваются идеи =/
Ответ №2:
Решение проблемы было сложным. Мне пришлось использовать * ngIf в mat-form-field, чтобы дождаться моей переведенной метки:
<mat-form-field *ngIf="isReady$ | async" [formGroup]="cityForm"
При выполнении перевода должно быть выполнено условие, поэтому мне пришлось сделать это в ngOnInit:
this.isReady$ = this.translate.get('translate_id').pipe(mapTo(true));
Таким образом, теперь элемент не отображается до того, как перевод будет возвращен из службы translate. Это обходной путь, но я не нашел другого решения.
Ответ №3:
Если вы используете changeDetection: ChangeDetectionStrategy.OnPush
стратегию
вы можете добавить AfterViewChecked
инструменты в свой компонент и
на ngAfterViewChecked
крючке добавьте следующий код:
ngAfterViewChecked() {
this._translateService.onLangChange.subscribe(() => {
this._changeDetectorRef.detectChanges()
});
}
При таком подходе вам не нужно что-то делать в шаблоне.
У меня это работает. Наслаждайтесь.