-1

I am trying to build an angular app containing two sibling components - Welcome & Questions. The Welcome template has a textbox for username and I want to display that username in my Question component template. For this, I have written a service to communicate between these two sibling components. Here are my codes -

username.service.ts

      export class UsernameService {
         name = new EventEmitter<string>();
      }

welcome.component.ts

    export class WelcomeComponent {
      username: string = '';
      @ViewChild('username') usernameInput: ElementRef;
      constructor(private unameService: UsernameService){}
      onStartQuiz(){
         this.username = this.usernameInput.nativeElement.value;//the value is correct      
         this.unameService.name.emit(this.username);
       }
    }

question.component.ts

    export class QuestionComponent implements OnInit {
       username: string = '';
       constructor(private unameService: UsernameService) { }
       ngOnInit(): void {
          this.unameService.name.subscribe((data) => {
          console.log(data); //This is not getting printed
        });
       }
      }

Inside subscribe, nothing is getting printed. I also tried using Subjects but then also the result is same. I have also provided the service in app.module .I am not able to understand what the problem is.

Vega
  • 27,856
  • 27
  • 95
  • 103
  • Did you register your service as a singleton? Otherwise, your two components will have different instances. You can achieve this by adding `@Injectable({ providedIn: 'root', })` decorator above your service. – Eldar May 18 '23 at 06:49
  • yes @Eldar, I have done this as well. Still it wasn't working. – Jewel Chakraborty May 18 '23 at 06:56

1 Answers1

0

Event emitters are not used in that way. If you want to communicate through a service, you need to use observables to subscribe to. Bear in mind you also need to unsubscribe from them when you destroy the component to prevent memory leaks.

username.service.ts

import { Subject } from 'rxjs/Subject';

export class UsernameService {

  private name = new Subject<string>();

  public name$ = this.name.asObservable();

  // Method to ensure the private name property can be set by the components.
  setName(name: string) {
    this.name.next(name);
  }
}

welcome.component.ts

export class WelcomeComponent {

  @ViewChild('username')
  public usernameInput: ElementRef;

  public username: string = '';

  constructor(
    private usernameService: UsernameService,
  ) { }

  onStartQuiz(){
    this.username = this.usernameInput.nativeElement.value;    
    this.usernameService.setName(this.username);
  }
}

question.component.ts

import { Subscription } from 'rxjs';

export class QuestionComponent implements OnInit {

  private nameSubscription: Subscription;
  
  public username: string = '';

  constructor(
    private usernameService: UsernameService,
  ) { }

  ngOnInit(): void {
    this.nameSubscription = this.usernameService.name$.subscribe(name => {
      this.username = name;
      console.log(this.username);
    });
  }

  ngOnDestroy() {
    this.nameSubscription.unsubscribe();
  }
}

You can accomplish the same with event emitters, if welcome.component.ts and question.component.ts are truly sibling components (i.e. if they have the same parent component). There is an excellent post detailing communication between components which you can find here: How to call another components function in angular2.

Leonardum
  • 444
  • 4
  • 8
  • Actually the problem was not using Subjects or EventEmitters. The issue was that Welcome and Question Component was not there in the view at the same time. When I am giving the username in the text box in welcome component, the question component is not there in the view yet. Thats why it's not able to catch the subscription. What I did is storing the value of username in a property in my service and then used it in the Question component. This is one of the solutions. Another solution is using Behavioral Subject. – Jewel Chakraborty May 22 '23 at 06:57