I am trying to update the value of an Array in my service from child component.
Here is the service at the top level of application
feature.service.ts
export class FeatureService {
private myFeatures: MyFeature[] = [
new Feature(1, '1st Empty String'),
new Feature(2, '2nd Empty String'),
new Feature(3, '3rd Empty String'),
];
getFeatures() {
return this.myFeatures.slice();
}
}
printFeatureArray() {
console.log(this.myFeatures);
}
As you can see it, it initialises MyFeatures Array to hold the most up date version of my data,
I would like to change this data through a child component, and be able to call the printFeatureArray function to print the updated values.
Here are the child components constructing my feature items from the getDocFeatures function generating a reference for display, this component is used to create individual items per instance.
component.ts
export class Component {
myFeatures: MyFeature[] | undefined;
constructor(private docBuilderService: DocBuilderService) {}
ngOnInit() {
this.myFeatures = this.FeatureService.getDocFeatures();
}
}
component.html
<div
class="list"
*ngFor="let myFeature of myFeatures; let i = index"
>
<app-my-item [docFeature]="docFeature"></app-my-item>
</div>
Finally from within the my-item component I have an input HTML element that I would like to record user input and populate the myFeatures Array on the very top level.
<input
#inputTag
(keyup)="getValue(inputTag.value)"
[ngClass]="addClassTemplate()"
(click)="onSelected()"
type="text"
placeholder="{{ docFeature?.inputValue }}"
/>
my-item.component.ts
export class MyItemComponent {
value: string | undefined;
constructor() {}
getValue(value: string) {
console.log(value);
}
}
How do i update the original Array inside the service from the bottom level of this component tree?
Thanks!
For a cross communication a Subject in a Service is the best practice.
myService
private mySubject: Subject<string> = new Subject();
getMySubject() {
return this.mySubject.asObservable();
}
doSomething(text: string) {
this.mySubject.next(text);
}
Code Behind
...
private mySub!: Subscription;
myTextData: string = "";
constuctor(private myService: MyService) {}
ngOnInit(): void {
this.mySub = this.myService.getMySubject().subscribe(data => { this.myTextData = data; }
}
ngOnDestroy(): void {
this.mySub.unsubscribe();
}
Components HTML
<div>
{{ myTextData }}
</div>
You can use an array
of objects, too. And then use it with *ngFor
. All the same. Every time the service calls the Subjects next
method, all components they subscribe to it will be updated.
Important We have the mySub
object which we unsubscribe
on ngOnDestroy
this is very important! Otherwise the subscription is multiplied and fires multiple times. Thats not what we want :-).
Second Important In the Service we'll never return the Subject
directly. Instead we return its Observable. Looks a little strange but that is the correctly way to do this and not a workaround.
All about this here.