CH4B
CH4B

Reputation: 774

Data binding failure, as the variable does not update its value

I have this 'errors' message component. It uses data-binding to get its text, so i just created a function that gets as parameter the message that should show. This is the idea:

<div id="success"> {{message}} </div>

The component:

  message: string = "Something went wrong";

  constructor() { }

  ngOnInit() {
  }

  callMessage(msg: string) {
    this.message= msg;
    $("#success").animate({
      'top': '10px'
    });
  }

You see, message gets its value from whoever is calling it. The problem is that inside the callMessage() function, the value does get updated, but the global varible is not changing. I looked this up in the web, and tried things like window.message and window[message], tho none of it seems to work. I have also tried removing that fixed message 'Something went wrong', but the variable just remains null. I have also tried calling the function from the ngOnInit, but without success, i can't delete the callMessage() and just paste it inside ngOnInit, because it does not accepts parameters.

That causes the message component to always show the fixed message (or nothing, without it). Funny thing is that this should work. Inside this very same project i did many other functions that work by changing global values, and the passing it t the DOM. But for some reason, this example seems to fail.

What could be causing this?

note: If you need any other piece of code, please feel free to say it, and just for clarification, the callMessage() is called in the main ngOnInit of the web-app

Edit: Someone asked for the decorator, so here's a better look:

import { Component, OnInit } from '@angular/core';
import * as $ from 'jquery';

@Component({
  selector: 'app-messages',
  templateUrl: './messages.component.html',
  styleUrls: ['./messages.component.css'],
  providers: [MessagesComponent]
})
export class MessagesComponent implements OnInit {

And this is how i'm calling it:

ngOnInit() {

  this.toggleSuccess('Test');

}

toggleSuccess(msg: string) {

  this.messagesComponent.callMessage(msg);

}

and of course, i have a <app-messages></app-messages> in the main.html

obs: those are separated methods because i'm usually calling the toggleSuccess from main, instead of extending the message to the full project (as the mainComponent is already provided)

Upvotes: 0

Views: 684

Answers (2)

Bardr
Bardr

Reputation: 2559

As @Arif stated in comments your approach is wrong.

There are two separate instances. What is displayed has nothing to do with what is being provided.

Among the other options you can use singleton service approach: StackBlitz demo (which is the best solution imho).

Upvotes: 1

Arif
Arif

Reputation: 1643

Your approach is not correct. You shouldn't inject components.

What you should do is:

Either - use @ViewChild and call it only in or after ngAfterViewInit

Or - Create a service, and use ComponentFactoryResolver to dynamically insert view.

Or - Create a singleton service (provide in root), create a Behaviour, listen to that subject from your error component.

@Injectable({
    provideIn: 'root'
})
export class ErrorService {
    public error = new BehaviourSubject(null);
}

Inject it to your app.component and send message

constructor(private errorService: ErrorService) {

}

ngAfterViewInit() {
    this.errorService.error.next('Your message');
}

And in your app-error component do this

  message: string = "Something went wrong";

  constructor(private errorService: ErrorService) { }

  ngOnInit() {
    this.errorService.error.subscribe(error => {
      if (error !== null) {
        this.callMessage(error);
      }
    })
  }

  callMessage(msg: string) {
    this.message= msg;
    $("#success").animate({
      'top': '10px'
    });
  }

Note: Please recheck my code for typos as I'm writing this using mobile phone.

Upvotes: 1

Related Questions