I have 2 components (Menu and Header) and one Service. What I want to do is that when they select an item from the menu, the menu sends the text to the service and the service sends it to the header and changes it. I already managed to send it to the service, but I do not know why in the header with the Observable it does not update.
Service:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import 'rxjs/add/observable/from';
import { of } from 'rxjs';
@Injectable()
export class passVarHelper{
currentIndex: string;
constructor(
){
this.currentIndex = "Title";
}
getIndex(): Observable <string> {
return of(this.currentIndex);
}
changeIndex(index:string){
this.currentIndex = index;
console.log(this.currentIndex);
}
}
Header:
import { Component, OnInit } from '@angular/core';
import { passVarHelper } from 'src/app/helpers/passVar.helper';
@Component({
selector: 'app-headerpage',
templateUrl: './headerpage.component.html',
styleUrls: ['./headerpage.component.css'],
providers: [passVarHelper]
})
export class HeaderpageComponent implements OnInit {
index:string;
constructor(private _passVarHelper: passVarHelper) {
}
ngOnInit() {
this.loadIndex();
}
loadIndex(){
this._passVarHelper.getIndex().subscribe(
response => {
if(response){
console.log(response);
this.index = response;
}
},
error => {
console.log(<any>error);
}
);
}
}
Menu:
import { Component, OnInit, Input, OnDestroy } from '@angular/core';
import { passVarHelper } from 'src/app/helpers/passVar.helper';
@Component({
selector: 'app-asidenavbar',
templateUrl: './asidenavbar.component.html',
styleUrls: ['./asidenavbar.component.css'],
providers: [passVarHelper]
})
export class AsidenavbarComponent implements OnInit {
constructor(private _passVarHelper: passVarHelper) {
}
ngOnInit() {
}
menuClick(){
var indexMenu = document.getElementById('menu').innerHTML;
this._passVarHelper.changeIndex(indexMenu);
}
}
Header HTML
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark">{{index}}</h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a href="#">Volver</a></li>
</ol>
</div>
</div>
</div>
</div>
Observable.of
is one time event, as per documentation:The last part about complete notification is important since once it's done (it's executed for the first time) it emits
complete
event and doesn't emit anymore. What you need to do is useSubject
orBehaviorSubject
in order to get constant stream of events.Try something like this:
Then
loadIndex
method:Here is stackblitz example demonstrating this behavior.
EDIT: Ok, I see where the problem is... It is in
providers
array, you cannot provide service inheader
normenu
components, you have to provide it in component that is above them (likeapp.module
orapp.component
). If you provide services in both of these components you will get different instance of the service and what you want to achieve will not work.Therefore, provide
passVarHelper
in either one of them (if another is child of the first one) or inapp.module.ts
providers array (check the stackblitz example I provided, I provided service inapp.module.ts
) and only in that one place (in order to get the same instance).Hmm, Angular has something called provider scope. For example, take a look at this definition:
That means that when you provide service at the root level, you will get a single instance of that service wherever you inject it using DI (like when you inject it in constructor).
But, you can also provide services in any other component. By providing a service in the component, you are actually limiting the service only to that component and components inside that component. Essentially, by providing a service in component, you will get a new instance of that service when you inject it in that component (and all its children will have that one instance, unless they themselves provide the service).
So, single instance of the service is used for the component and all its children, but if provided in any child component, that child and all its children will get the new instance.
Hope this makes it a bit more clearer.
Interesting reading material:
Hey I think you should look into this section for component interaction on the Angular docs: https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service
You update the
currentIndex
variable, but I don't believe that triggers the Observable to update properly. ThecurrentIndex
should be an Observable variable that you can subscribe to and listen for changes in the variable.Create your observable as a class level variable in your service and assign values to it using
.next()
Something like this (I haven't tested the code, just conceptually edited it):
In the header component
In the header template (html), bind the index using async pipe