so I'm trying to upload an image from the user's gallery to my API. Currently, I can select the image from the gallery but it's not letting me pass that selected image into another function to send it to the API. There is no problem with the API, that has been tested. I am using the "nativescript-imagepicker" plugin
This is the code:
getImage() {
let context = imagepicker.create({
mode: "single" // use "multiple" for multiple selection
});
context
.authorize()
.then(function () {
return context.present();
})
.then(function (selection) {
selection.forEach(function (selected) {
console.log(selected)
this.uploadImage(selected)
});
})
.catch(function (e) {
console.log('error')
// process error
});
}
uploadImage(imageAsset) {
console.log('uploading image')
let token = JSON.parse(appSettings.getString('token'));
let options = new HttpHeaders({
"Content-Type": "application/x-www-form-urlencoded",
// "Content-Type": "application/octet-stream",
"Authorization": "Bearer " + token
});
let userId = appSettings.getString('currentUserId')
let url = 'http://localhost:5000/api/users/' + userId + '/photos'
console.log(url)
this.http.post(url, imageAsset, { headers: options }).subscribe(res => {
console.log(res)
console.log('Success')
}, error => {
console.log('Failed');
});
}
It runs the getImage function and takes me to the gallery, then once the image is selected, it runs the console.log function (which works so the image is being received I believe & it logs the route to the image). This is the output for the console.log
{
JS: "_observers": {},
JS: "_options": {
JS: "keepAspectRatio": true,
JS: "autoScaleFactor": true
JS: },
JS: "_android": "/storage/emulated/0/DCIM/Camera/IMG_20200211_200350.jpg"
JS: }
It doesn't, however, run the 'this.uploadImage' function with the image, so instead it skips over this and goes to the '.catch' block and logs 'error'. It also logs this in the console
ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'uploadImage' of undefined
JS: TypeError: Cannot read property 'uploadImage' of undefined
JS: at file:///src\app\_mocks\test\test.component.ts:38:25
JS: at Array.forEach (<anonymous>)
JS: at file:///src\app\_mocks\test\test.component.ts:36:30
JS: at ZoneDelegate.push.../node_modules/nativescript-angular/zone-js/dist/zone-nativescript.js.ZoneDelegate.invoke (file:///node_modules\nativescript-angular\zone-js\dist\zone-nativescript.js:388:0)
JS: at Object.onInvoke (file:///node_modules\@angular\core\fesm5\core.js:26256:0)
JS: at ZoneDelegate.push.../node_modules/nativescript-angular/zone-js/dist/zone-nativescript.js.ZoneDelegate.invoke (file:///node_modules\nativescript-angular\zone-js\dist\zone-nativescript.js:387:0)
JS: at Zone.push.../node_modules/nativescript-angular/zone-js/dist/zone-nativescript.js.Zone.run (file:///data/d...
Imports
import * as fs from "tns-core-modules/file-system";
import * as camera from "nativescript-camera";
Functions
// This method allows the user to take a picture, save to the gallery, display it on the screen, convert it to base64 and then send it to the API
Take picture, save to gallery, save as a base64 string, display on the screen
takePicture() {
const options = { width: 300, height: 300, keepAspectRatio: false, saveToGallery: true };
camera.takePicture(options).
then((imageAsset) => {
console.log("Size: " + imageAsset.options.width + "x" + imageAsset.options.height);
console.log("keepAspectRatio: " + imageAsset.options.keepAspectRatio);
console.log("Photo saved in Photos/Gallery for Android or in Camera Roll for iOS");
const imgPhoto = new ImageSource();
const that = this;
imgPhoto.fromAsset(imageAsset).then((imgSrc) => {
if (imgSrc) {
// This is the base64 string, I saved it to a global variable to be used later
that.bstring = imgSrc.toBase64String("jpg");
console.log(that.bstring);
// This bit saves it as an 'Image' to the app
const mil = new Date().getTime();
const folder = fs.knownFolders.documents();
const path = fs.path.join(folder.path, `SaveImage${mil}`);
const saved = imgPhoto.saveToFile(path, "png");
// This saves the image to the global variable which will be used to display it on the screen
that.saveImage = path;
that.picHeight = imgSrc.height;
} else {
alert("Image source is bad.");
}
});
}).catch((err) => {
console.log("Error -> " + err.message);
});
}
Send it to the API
// This is just a generic API call that uses the base64 string as the image
// you can choose whether to call the function and pass the image into it, or just use the one saved in the global variable
uploadImage(image = null) {
const imageString;
if (image) {
let imageString = image
} else {
imageString = this.b64image
}
// This is where you create the object to be sent up to the API, in this example I'm sending up a description aswell, so I've added the property here
const data = {
B64String: imageString,
Description: this.imageDescription
};
// This is where i create my headers, in this case I'm using authorization
const headers = new HttpHeaders({
Authorization: "Bearer " + appSettings.getString("tok")
});
// This is my API call
this.http.post(this.baseUrl + "users/" + this.userId + "/photos", data, { headers})
.subscribe((res) => {
console.log(res)
}, (error) => {
console.log(error)
}
}