Search code examples
angularngx-translate

Ngx-translate, Angular could not detect JSON address string change


I am currently working on a project which requires me to use Ngx-translate, so I applied it to the project. I have created a separate translation module and I was able to use a translation pipe across the project(Gather from various example projects). However, I still can not use it to get json with an array of array values. I want to get the json address string so that when I change the language it would also change the whole questionsM1[]. The purpose of doing this is so that I can get this.questionList.length. the Idea is that the page will show only one question, and when answered then it will advance to the next.

For better understanding here are my codes

translate.module.ts

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

@NgModule({
  imports: [
    CommonModule,
    HttpClientModule,
    TranslateModule.forRoot({
      defaultLanguage: 'en',
      loader: {
        provide: TranslateLoader,
        useClass: QuestionsService, //add this to export TranslateHttpLoader ?
        useFactory: HttpLoaderFactory,
        deps: [HttpClient],
      },
      compiler: {
        provide: TranslateCompiler,
        useClass: TranslateMessageFormatCompiler,
      },
    }),
  ],
  exports: [TranslateModule],

questions.service

export class QuestionsService implements TranslateLoader, OnInit {
 
  languageSelection: string = `assets/i18n/`+ this.translate.defaultLang+`.json`;

  constructor(private http: HttpClient, private translate: TranslateService) {}

  ngOnInit(): void {
    //this.getQuestionsJson();
  }

  getTranslation(lang: string): Observable<any> {
    this.languageSelection = `assets/i18n/${lang}.json`;
    console.warn('getTranslation : ' + this.languageSelection);
    this.translate.use(lang);
    this.getQuestionsJson();
    return this.http.get<any>(this.languageSelection).pipe(
      map((response: any) => {
        console.log('This JSON : ' + response.json);
        return response.json();
      })
    );
  }

  getQuestionsJson() {
    console.warn('get newJson : ' + this.languageSelection);
    this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
      const lang = event.lang;
      this.translate.use(event.lang);
      console.log('Lang event : ' + lang);
    });
    return this.http.get<any>(this.languageSelection);
  }
}

q.component.ts

 public questionList: any = [];
 public currentQuestion: number = 0;
 progress: string = '0';
 public points: number = 0;
 correctAnswer: number = 0;
 inCorrectAnswer: number = 0;
 isQuizCompleted: boolean = false;
 option: any;
 thisTypeOfKeyWorks = 'only 1-2 layer works not array of arrays';

constructor(
    private questionService: QuestionsService,
    private translate: TranslateService

  ) {
   
  }

  ngOnChanges(changes: SimpleChanges): void {
    // this.getAllQuestions;
  }

  ngOnInit(): void {
    this.getAllQuestions();
    this.imageArrayToDisplay = this.imageArray.slice(0, this.displaySize);
  }

  getAllQuestions() {
    this.questionService.getQuestionsJson().subscribe((res) => {
      this.questionList = res.questionsM1;
      console.log('array questions[] : ' + res.questionsM1);
    });
  }


####q.component.html

 <ng-container *ngIf="!isQuizCompleted">
      <div class="d-inline-flex justify-content-center py-2">
        <div class="score float-start">
          <h5>{{ points }} Points</h5>
        </div>
        <div class="question-remain px-3">
          <span style="font-style: italic"
            >Question {{ currentQuestion + 1 }} of
            {{ questionList.length }}</span
          >
        </div>
      </div>
      <div class="progress mb-2">
        <div
          class="progress-bar progress-bar-striped bg-success"
          role="progressbar"
          [ngStyle]="{ width: progress + '%' }"
          aria-valuenow="25"
          aria-valuemin="0"
          aria-valuemax="100"
        ></div>
      </div>

      <div class="question">
        <div class="card">
          <h3>{{ questionList[currentQuestion]?.questionText | translate }}</h3>
        </div>
      </div>
      <div class="options">
        <ol *ngFor="let option of questionList[currentQuestion]?.options">
          <li (click)="answer(currentQuestion + 1, option)">
            <div appChangeBg [isCorrect]="option.correct" class="card">
              {{ option.text | translate }}
            </div>
          </li>
        </ol>
      </div>
   
    </ng-container>

<p>{{ thisTypeOfKeyWorks | lowercase | translate: { case: "lowercase" } }}</p>

en.json

{

 "thisTypeOfKeyWorks": "only 1-2 layer works not array of arrays",

    "questionsM1": [{
            "questionText": "1+1-2 = ?",
            "options": [{
                    "text": "0",
                    "correct": true
                },
                {
                    "text": "4"
                },
                {
                    "text": "2"
                },
                {
                    "text": "No answers are correct."
                }
            ],
            "explanation": "loremipsum"
        },
        {
            "questionText": "text ?",
            "options": [{
                    "text": "123"
                },
                {
                    "text": "ok300"
                },
                {
                    "text": "777"
                },
                {
                    "text": "56456",
                    "correct": true
                }
            ],
            "explanation": "loremipsum"
        }]
}

The json address string changed. The key value from json file were also translated(because of the pipe) except for the questionsM1[], which requires string change detection in order to return httpClient.

enter image description here

I just want to make it like, when you change the json address the whole questionM1[[object Object],[object Object]] also get translate. I mean the string address changed, but somehow it still does not detect any changes (I have tried putted it in OnInit and Onchanges).

How should one solve this ?


Solution

  • After I have looked into the Ngx-translate source code. They provide you with plenty of options to play with. In this case I just simply subscribe to onLangChange event

    like this

    Component

      ngOnInit(): void {
        this.getAllQuestions(); 
        this.imageArrayToDisplay = this.imageArray.slice(0, this.displaySize);
      }
    
      getAllQuestions() {
            //Important part//
         this.translate.onLangChange.subscribe((event: LangChangeEvent) => { 
          this.questionService.getQuestionsJson(event.lang).subscribe((res) => {
             this.questionList = res.questions;
             console.log('array questions[] : ' + res.questions);
           });
         });
      }
    

    questions.service

    constructor(private http: HttpClient, private translate: TranslateService) {
         this.translate.use('en');
      }
      
     getQuestionsJson(lang: string){
         console.warn('get newJson : ' + this.languageSelection);
        if (lang) {
          this.languageSelection = `assets/i18n/${lang}.json`;
        }
         if (!lang) {
           this.translate.use('en'); 
         }
        return this.http.get<any>(this.languageSelection);
      }