angularfilepicker.io

Filestack with Angular 2


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?


Solution

  • 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.