Issue
I created a subscription in my template to watch for changes to an object. The initial loading of the object displays the correct data for the property tags
, when I add an item to the data it goes to a web server and returns a list of all the tags
that are attached to the item (to keep the item in sync with the server). However, the newly added item isn't reflected on the page. I am not 100% sure why. I think it is because my of()
statement but I am not sure. What I am seeing is that zip().pipe()
never gets executed.
Do I need to use something other than of
?
Note: I am trying to follow the declarative pattern to eliminate the usage of .subscribe()
Sub-Note: Once I get it working I plan on trying to remove the subscribe
on this line this.server.file().subscribe
export interface FileInfo {
tags: string[];
}
@Component({
selector: 'my-app',
template: `
<input #tag /><button (click)="addTag(tag.value)">Add Tag</button>
<div *ngIf="data$ | async as data">
<div *ngFor="let tag of data.tags">{{ tag }}</div>
</div>
`,
})
export class AppComponent {
data$ = new Observable<FileInfo>();
constructor(
// Used to mimic server responses
private readonly server: WebServer
) {}
ngOnInit() {
// I plan on removing this subscribe once I get a grasp on this
this.server.file().subscribe((img) => {
this.data$ = of(img);
});
}
addTag(newTag: string) {
const data$ = this.server.save(newTag);
this.data$.pipe(concatMap((i) => this.zip(data$)));
}
private zip(tags$: Observable<string[]>) {
return zip(this.data$, tags$).pipe(
tap((i) => console.log('zipping', i)),
map(([img, tags]) => ({ ...img, tags } as FileInfo))
);
}
}
Solution
It sounds like what you want to do is have a single observable source that emits the latest state of your object as new tags are added. Then you can simply subscribe to this single observable in the template using the async pipe.
In order to accomplish this, you can create a dedicated stream that represents the updated state of your file's tags.
Here's an example:
private initialFileState$ = this.service.getFile();
private addTag$ = new Subject<string>();
private updatedfileTags$ = this.addTag$.pipe(
concatMap(itemName => this.service.addTag(itemName))
);
public file$ = this.initialFileState$.pipe(
switchMap(file => this.updatedfileTags$.pipe(
startWith(file.tags),
map(tags => ({ ...file, tags }))
))
);
constructor(private service: FileService) { }
addTag(tagName: string) {
this.addTag$.next(itemName);
}
Here's a StackBlitz demo.
Answered By - BizzyBob
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.