You don't need to do any decoding. Your title says you are using AngularJS which is not Angular (which you tagged). AngularJS is not recommended for new development so I assume you are dealing with some legacy app.
For AngularJS you are bumping up against the classic problem of events or promises landing outside of AngularJS's digest in which case the common solution is to use $scope.apply()
. An easy to understand description of $scope.apply()
look here.
If you are actually using Angular instead of AngularJS you would use zone.run
instead, see this SO Q/A.
The snippet below is a bare bones AngularJS app that looks up a base64 encoded jpeg attachment and displays it once loaded.
As an aside, setting methods like this
reader.onloadend = () => {
Is not good practice and likely results in memory leaks. Instead create the event handler, use it and dispose of it when done, as in the snippet. For example for a one-shot event,
element.addEventListener("someEvent", () => {
// clean up don't, leak stuff
element.removeEventListener("someEvent", this);
});
const jpegData =
`/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAEMuMjoyKkM6NjpLR0NPZKZsZFxcZMySmnmm8dT++u3U6eX//////////+Xp////////////////////////////2wBDAUdLS2RXZMRsbMT//+n/////////////////////////////////////////////////////////////////////wgARCABAAEADAREAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAP/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQP/2gAMAwEAAhADEAAAAZ6wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/8QAFBABAAAAAAAAAAAAAAAAAAAAYP/aAAgBAQABBQIB/8QAFBEBAAAAAAAAAAAAAAAAAAAAYP/aAAgBAwEBPwEB/8QAFBEBAAAAAAAAAAAAAAAAAAAAYP/aAAgBAgEBPwEB/8QAFBABAAAAAAAAAAAAAAAAAAAAYP/aAAgBAQAGPwIB/8QAFBABAAAAAAAAAAAAAAAAAAAAYP/aAAgBAQABPyEB/9oADAMBAAIAAwAAABDbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/xAAUEQEAAAAAAAAAAAAAAAAAAABg/9oACAEDAQE/EAH/xAAUEQEAAAAAAAAAAAAAAAAAAABg/9oACAECAQE/EAH/xAAUEAEAAAAAAAAAAAAAAAAAAABg/9oACAEBAAE/EAH/2Q==`;
let db;
// init example db instance
function initDb() {
db = new PouchDB('test', {
adapter: 'memory'
});
let doc = {
_id: "Purple Box",
"_attachments": {
"thumbnail": {
"content_type": "image/jpeg;base64",
"data": jpegData
}
}
}
return db.put(doc);
};
var app = angular.module("pouchy", []);
app.controller("pouchyAttachment", async($scope) => {
// setup the test database
await initDb();
let attachment = await db.getAttachment("Purple Box", "thumbnail");
$scope.attachment = attachment;
let reader = new FileReader();
// setup image after attachment blob is loaded
reader.addEventListener("loadend", () => {
$scope.image = reader.result;
// this is outside the AngularJS, must use $scope.apply() to get update.
$scope.$apply();
// clean up don't leak stuff
reader.removeEventListener("loadend", this);
});
reader.readAsDataURL(attachment);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<script src="https://github.com/pouchdb/pouchdb/releases/download/7.1.1/pouchdb-7.1.1.min.js"></script>
<script src="https://github.com/pouchdb/pouchdb/releases/download/7.1.1/pouchdb.memory.min.js"></script>
<div ng-app="pouchy" ng-controller="pouchyAttachment">
<div>Type: {{attachment.type}}</div>
<div>Size: {{attachment.size}}</div>
<img id="pouchyImage" src="{{image}}" />
</div>
Update
If you are in fact using Angular as opposed to AngularJS, you need to jump through a few hoops.
As an example, setup a property binding like so
<img [src]="image" />
For a component, add DomSanitizer and NgZone
import { NgZone, Component } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
/*etc*/
constructor(private sanitizer: DomSanitizer, private zone: NgZone, /*etc*/) {
/*etc*/
}
The DomSanitizer is used so the image data is otherwise marked as safe; NgZone so the property change to the src
binding is detected and processed.
So something like this will do the trick
// some method body
let attachment: Blob = (await db.getAttachment(docId, attachmentName")) as Blob;
const reader = new FileReader();
const _zone = this.zone;
const handler = () => {
_zone.run(() => {
this.image = this.sanitizer.bypassSecurityTrustUrl(reader.result as string);
reader.removeEventListener("loadend", handler);
});
};
// setup image after attachment blob is loaded
reader.addEventListener("loadend", handler);
reader.readAsDataURL(attachment as any);