I'm trying to add an option to add an image in my Angular 2 App and wanted to use Filestack (formerly filepicker.io) to store the images.
So I included these script tags in my index html file above </body>
, as Filestack suggested (and put my API key in) and added the <input>
field in my component html which displays the form to add a new recipe:
in index.html:
<script src="https://static.filestackapi.com/v3/filestack-0.5.0.js"></script>
<script>
var url = '';
var client = filestack.init('myApiKey');
function showPicker() {
client.pick({
maxFiles: 1
}).then(function(result) {
url = JSON.stringify(result.filesUploaded[0].url)
});
}
</script>
in recipe-form.component.html:
<input type="button" value="Upload" onclick="showPicker()" />
Now that works perfectly fine, it uploads the image and if I add console.log(url)
it also shows the url of the image. However, there seems to be no way to get that variable into the RecipeFormComponent where I want to add the url to the object I'm creating there. How could I do that?
I have found a lot of stuff about how to use Filestack with AngularJS, but not how to do this in Angular 2...
Is there anything you know of that could help me?
Remove everything you have shown for index.html except for the script tag to load the API.
<script src="//static.filestackapi.com/v3/filestack-0.5.0.js"></script>
Then alter your component to incorporate the showPicker
functionality
recipe-form.component.ts
declare const filestack: {
init(apiKey: string): {
pick({ maxFiles }: { maxFiles: number }):
Promise<{ filesUploaded: { url: string }[] }>
}
};
@Component({
// boilerplate and ceremony
})
export class RecipeFormComponent {
uploadedFileUrls: string[] = [];
async showPicker() {
const client = filestack.init('myApiKey');
const result = await client.pick({ maxFiles: 1 });
const url = result.filesUploaded[0].url;
this.uploadedFileUrls.push(url);
}
}
To improve maintainability and testability, you should move all of the code with that accesses the filestack
global into a dedicated service or services.
For example we could write a service like
// file-upload.service.ts
declare const filestack: {
init(apiKey: string): {
pick: (options: {maxFiles: number}) => Promise<{filesUploaded: {url: string}[]}>
}
};
const client = filestack.init('myApiKey');
export default class {
async uploadOne() {
const result = await client.pick({ maxFiles: 1 });
return {urls: result.filesUploaded.map(uploaded => uploaded.url)};
}
}
we can consume it from components by using the service which wraps the API and provides the results that matter to our application
import FileUploadService from 'app/services/file-upload.service';
@Component({
// boilerplate and ceremony
})
export class RecipeFormComponent {
constructor(readonly fileUploadService: FileUploadService) {}
uploadedFileUrls: string[] = [];
async showPicker() {
const {urls: [url]} = await this.fileUploadService.uploadOne();
this.uploadedFileUrls.push(url);
}
}
Additionally, if you're using a module loader like SystemJS, you would do well to remove the script tag itself, mapping and hiding its global nature via the loader.