Handling Promise and Observable on same variable in Node.js & Angular

In my project, I have an image.

On initialization; I load it from a Promise<string>; where string is a URL to the image

Then I use a node package to change and crop the image. It asks for an image, crops it to the requested size and returns an Observable<anObject> where the anObject.base64 is a base64 representation of the cropped image. It's contained in a dialog.

I tried many many things but could not change the image of the <img> tag automatically.

Here is my last setup:

image: Observable<string>;
...

ngOnInit() {

    ...

    prd.images.big.then(img => {
        this.image = of(img);
    });
    // prd.images.big is a Promise<string>

    ...
}


showImageDialog() {
    this.image = this.imageDialog.openDialog().pipe(
        map(data => {
            return data.base64;
        })
    );
}

And my template: ....

<a style="cursor: pointer" (click)="showImageDialog();">
    <img [src]="(image | async) || 'an url to default image'"/>
</a>

....

Weird thing is, image not change automatically, but when I click on the image again, it changes.

I hope any of you can help to achieve this. Thank you.

Upvotes: 0

Views: 300

Answers (2)

Brandon
Brandon

Reputation: 39222

You want to avoid re-assigning the observable once you create it. Try something like this:

image: Subject<string>;
...

ngOnInit() {

    this.image = new ReplaySubject<string>(1);

    prd.images.big.then(img => this.image.next(img));
}

showImageDialog() {
    this.imageDialog.openDialog().subscribe(data => {
       const dataUrl = `data:image/jpeg;base64,${data.base64}`;
       this.image.next(dataUrl);
    });
}

FYI a Subject is just a variable that acts as both observer and observable-you can subscribe or pipe operations from it like any observable and you can also manually put values into the subject that will then be observed by all of the subscribers. In the code above I used a special kind of subject that will replay the most recent value to any late subscribers just in case you put a value in before the view has time to subscribe.

Upvotes: 1

Dave B
Dave B

Reputation: 69

You are currently assigning a subscription to this.image. Instead, set this.image to be the data.base64 returned inside your map function. If you want to use base64-encoded image bytes for an image tag, you need to use a data URL

If your image type is jpeg: <img src="data:image/jpeg;base64,{{image}}"/>

Upvotes: 1

Related Questions