Search code examples
angulareventemitterangular8

Angular 8 subscribe to an emitted event using emit giving an error of undefined ON method


EDIT

I have at the main-navbar.component the main menu of the whole app, which contains a drop list to change the default language of the app:

<form [formGroup]="langForm" role="form" *ngIf="langForm">
     <mat-form-field>
        <mat-select formControlName="selectLang" [(ngModel)]="selectedLang" (selectionChange)="OnChangeLang()">
             <mat-option value="en">English</mat-option>
             <mat-option value="ar">عربي</mat-option>
         </mat-select>
     </mat-form-field>
</form>

In OnChangeLang() method, I need to change the default language and default dir of the app that are saved in a service called global-var.service.ts:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class GlobarVarService {
  defaultLang:string = "en";
  defaultDir:string = "ltr";
  constructor() {
  }
}

These variables are connected to variables at app.component.ts.

I need to use BehaviorSubject to subscribe to the change made on these variable so it directly change the display of my app.

END EDIT

I have the following event to be emitted when a user change application default language:

@Output() changeLangOutput= new EventEmitter();
OnChangeLang()
{
  let lang = this.langForm.get('selectLang').value;
  console.log(lang)
  this.globalVar.defaultLang = lang;
  this.changeLangOutput.emit('changeLang', lang);

}

At the app.module.ts, I am trying to subscribe to this change using:

@Input() subscribeLangEvent: string;

but I have no idea how to do it, as subscribeLangEvent.on('changeLang) giving an error of on is undefined function.


Solution

  • I'm assuming from your comments that MainNavComponent is the child of the AppComponent.

    Here's how you'd implement the feature:

    In the Child Component, you'd expose an @Output property that you'd emit the value from:

    import { Component, Output, EventEmitter } from '@angular/core';
    import { FormGroup, FormBuilder } from '@angular/forms';
    
    @Component({
      selector: 'app-main-nav',
      templateUrl: './main-nav.component.html',
      styleUrls: ['./main-nav.component.css']
    })
    export class MainNavComponent {
    
      @Output() changeLangOutput= new EventEmitter();
    
      langForm: FormGroup;
      languageOptions: Array<string> = [
        'English',
        'Hindi',
        'Spanish',
        'French',
      ];
    
      constructor(private fb: FormBuilder) {}
    
      ngOnInit() {
        this.langForm = this.fb.group({
          selectLang: ['English']
        });
      }
    
      onChangeLang() {
        let lang = this.langForm.get('selectLang').value;
        this.changeLangOutput.emit(lang);
      }
    
    }
    

    And in the AppComponent Template, you'd listen to the event like this:

    <app-main-nav 
      (changeLangOutput)="onLanguageChange($event)">
    </app-main-nav>
    

    And in the AppComponent Class, define a method named onLanguageChange($event)


    UPDATE:

    Since you want multiple things from the selected value, you should have an array of objects instead of an array of strings.

    And when the user selects a different language, you'll get the value of the field as a string. But then you'll have to get the whole object from the list by using find:

    ...
    
    export class MainNavComponent {
    
      ...
    
      languageOptions: Array<{ id: number; name: string, direction: string }> = [
        { id: 1, name: 'English', direction: 'ltr'},
        ...
      ];
    
      constructor(private fb: FormBuilder) {}
    
      ngOnInit() {
        this.langForm = this.fb.group({
          selectLang: ['English']
        });
      }
    
      getLanguageObject(selectedLanguage) {
        return this.languageOptions.find(language => language.name === selectedLanguage);
      }
    
      onChangeLang() {
        const lang = this.langForm.get('selectLang').value;
        const selectedLanguage = this.getLanguageObject(lang);
        this.changeLangOutput.emit(selectedLanguage);
      }
    
    }
    

    Here's an Updated Working Sample StackBlitz for your ref.