cimfalab / vue-upload

A simple, light weight and intuitive upload control for Vue.js.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Vue Upload

A simple, light weight and intuitive upload control for Vue.js.

Features:

  • Drag and drop file zone.
  • Progress indicators
  • Synchronous or asynchronous modes.
  • Validation

Install

$ sudo npm install @websanova/vue-upload

Require in the project.

Vue.use(require('@websanova/vue-upload'));

Usage

At a minimum you will need to at least provide a url when creating a new $upload instance.

this.$upload.on('profile-avatar', {
    url: 'users/1/avatar'
});

It's likely things like the id would not be static so use the option method to update any options.

created() {
    this.$upload.on('profile-avatar', {
        onSuccess(res) {
            // Update user
        }
    });
},

mounted() {
    this.$upload.option('profile-avatar', {
        url: 'users/' + this.user.id + '/avatar'
    });
},

Check the Examples section below for more use case scenarios.

Files

All files will be in an array even if multiple is set to false.

You can fetch the full list of files with the files method.

<div v-for="file in $upload.files('product-gallery').all">
    {{ file.name }} <br/>
    {{ file.size }} <br/>
    {{ file.type }} <br/>
    {{ file.state }} <br/>
    {{ file.percentComplete }} <br/>
    {{ file.errors | json }}<br/>
</div>

This will return a variety of queues to use for processing, such as all, queue, progress. Just console it out for the full list.

There is also a shortcut to fetch the last file added.

$upload.file('profile-avatar');

All files contain the following meta data:

$id

For reference and to key in loops.

$file

Reference to raw file object from browser.

name

The name of the file.

size

The size of the file.

type

The mime type of the file.

extension

Extension of the file from filename then mimetype based on what is available.

state

Current state of the file which will be either queue, progress, upload, error or success.

percentComplete

Percent progress indicator for the file as an integer (0 to 100);

errors

Errors from file.

Note that errors can come internally from the module itself or externally from an error on the server end.

Use parseErrors option when installing the plugin to format errors from the server.

The internal default format is: [{code: 'somecode', msg: 'There was an error.''}]

Errors

The plugin also includes an errors object that includes a full stack of local and file errors.

For instance checking valid extensions or size is done locally in the browser and will add an internal error.

Some cases like total files selected exceeded the count set can also throw an error without a file. In this the file object in the error will be null.

Methods

on

This is used to create a new "upload" instance.

  • An upload instance is tracked in a global state.
  • Existing states will not be overwritten so you can call on multiple times without worry (use option for updating options).
  • It will always contain the current components instance when using this.

Typically a combination of on and off will be used. It's mostly semantic but it's nice to keep the separation.

The bind option can also be used to re-bind the instance to the current context.

created() {
    this.$upload.on('profile-avatar', {
        onSuccess(res) {
            this.$msgbag.success('Avatar uploaded successfully.');
            this.$auth.user(res.data.data);
        },
        onError() {
            this.$msgbag.error('Error uploading avatar.');
        }
    });
},

mounted() {
    this.$upload.option('profile-avatar', {
        url: 'users/' + this.$auth.user().id + '/avatar'
    });
},

off

Destroy the upload instance. It's good to not leave these lingering around.

Note it should be fine to just use on without problems, but this is here as a safety and for performance issues.

reset

This will completely reset the instance.

Also check the on option for more details.

  • An instance using on must be created first.
mounted() {
    this.$upload.reset('profile-avatar');
},

It's also useful to call reset() for clearing an upload when using multiple.

For instance a "clear" button.

<button v-on:click="$upload.reset('product-gallery')">
    Clear
</button>

select

This is used to trigger the browsers file select popup/dialog.

  • It's important to note that by default the uploads will start once files are selected.
  • Set startOnSelect option to false to prevent uploads from beginning after selection.
<button v-on:click="$upload.select('brand-logo')">
    Update Photo
</button>

start

This option is to be used in conjunction with the startOnSelect option when it's set to false.

  • It allows manual triggering of the upload.
<img :src="brandLogo" />

<button v-on:click="$upload.select('brand-logo')">
    Select Photo
</button>

<button v-on:click="$upload.start('brand-logo')">
    Upload Photo
</button>

files

Contains arrays of files currently being processed.

  • It contains multiple queues that can be used to display file data for viewing.
  • The queues are all, queued, progress, upload, success, error.
  • The array will not reset after completing (use reset and onEnd for that).
<div v-for="file in $upload.files('product-gallery').progress">
    {{ file.name }}: {{ file.percentComplete }}%
</div>

<div v-for="file in $upload.files('product-gallery').queued">
    {{ file.name }}: Queued for upload
</div>

meta

Fetches some meta info about the current uploads.

The meta info is fully reactive an can be used directly in the templates.

{{ $upload.meta('product-gallery').percentComplete }}%

It contains the following properties:

state

It will be either ready, sending, error, success. Check the Errors section above for more info.

percentComplete

Keeps track of progress for the currently uploading files.

dropzone

For use with drag/drop files to upload into a "drop zone".

  • Primarily used to be able to trigger an overlay when using a drop container.
  • This does NOT use the "dropzone" library.
<div v-show="$upload.dropzone('product-gallery').active">
    Drop files anywhere here to begin upload.
</div>

errors

This returns the global error state for the upload instance.

  • This will not return the individual file errors.
<div v-if="$upload.errors('product-gallery').length">
    <div v-for="error in $upload.errors('product-gallery')">
        {{ error.code }}: {{ error.message }}
    </div>
</div>

remove

Used for removing a single file from the files arrays.

  • This will remove the file from all files arrays where it exists.
$upload.remove('product-gallery', file);

option

Update an option without resetting the uploads.

  • Useful if a url or body param needs to be changed.
$upload.option('product-gallery', 'key', 'val');

dropzone

Reset the dropzone without resetting the uploads.

  • Useful if there is a global upload but only triggers via a dropzone on a specific page.
$upload.dropzone('product-gallery', 'id');

Options

url: null

This is required and sets the end point for the upload.

name: 'file'

The "name" to use for the upload file.

body: {}

Any additional form data to be sent with the upload.

onSelect: null

Triggered when files are selected.

onStart: null

Triggered once upload begins.

onQueue: null

Triggered once a file is moved into queue.

onProgress: null

Triggered once a file begins to upload.

onUpload: null

Triggered once the file is uploaded but still waiting for response from server.

onError: null

Triggered if file has an error (front or back end).

onSuccess: null

Triggered when server sends back a success.

onComplete: null

Triggered after either error or success.

onEnd: null

Triggered when currently uploading files all complete.

parseErrors: _parseErrors

Used to parse errors from server end.

It must return an array of objects in the format: [{code: 'someerror', msg: 'There was an error.'}]

http: _http

By default the plugin "assumes" Vue.http from vue-resource is used.

However this can be easily overridden.

It contains five parameters: url, body, progress, success, error.

function _http(data) {
    this.Vue.http.post(data.url, data.body, {progress: data.progress}).then(data.success, data.error);
}

Example using Axios:

function _http(data) {
    axios.get(data.url)
      .then(data.success)
      .catch(data.error);
}
function _parseErrors(error) {
    // in this example, the backend is returning JSON with a 'detail' field
    if (error.response.data.detail) {
        return [{code: 'fileError', msg: error.response.data.detail}];
    }

    return [];
}

multiple: false

For multiple file uploads this must be set to true.

maxFilesInProgress: 2

Set the maximum number of uploads that can run in parallel when async is set to true.

startOnSelect: true

To disable the upload from beginning automatically set this to false.

extensions: ['jpeg', 'jpg', 'png', 'gif']

The set of valid extensions allowed for upload.

Set to false to ingore this check.

maxFilesSelect: 4

The maximum number of files allowed for upload.

Note that this works in conjunction with currentFiles for a set maximum.

maxSizePerFile: 1024 * 1024 * 2

Set the maximum size per file in bytes

dropzoneId: null

You can set this to a DOM element ID to automatically assign the necessary drag and drop events to the element.

Important to note that (to be safe) the dropzone should always be unloaded when leaving the component it is called in.

created() {
    this.$upload.on('product-gallery', {
        multiple: true,
        dropzoneId: 'product-gallery-dropzone',
    });
},

mounted() {
    this.$upload.option('product-gallery', {
        url: `products/${this.product.id}/gallery`,
    });
},

beforeDestroy() {
    this.$upload.off('product-gallery');
},

Examples

Some common scenarios likely to be encountered when doing an upload and how $upload can handle them.

Single File (Profile Avatar)

A simple profile avatar upload with button, state and errors.

<img :src="$auth.user().avatar || '//www.gravatar.com/avatar/?d=mysteryman&s=200'" />

<div>
    <button v-on:click="$upload.select('profile-avatar')" :disabled="$upload.meta('profile-avatar').state === 'sending'">
        <span v-show="$upload.meta('profile-avatar').state === 'sending'">Updating...</span>
        <span v-show="!$upload.meta('profile-avatar').state === 'sending'">Update Photo</span>
    </button>
</div>

<div v-if="$upload.files('profile-avatar').error.length">
    {{ $upload.files('profile-avatar').error[0].errors[0].message }}
</div>
created() {
    this.$upload.on('profile-avatar', {
        onSuccess(res) {
            this.$msgbag.success('Avatar uploaded successfully.');
            this.$auth.user(res.data.data);
        },
        onError() {
            this.$msgbag.error('Error uploading avatar.');
        }
    });
},

mounted() {
    this.$upload.option('profile-avatar', {
        url: `users/${this.$auth.user().id}/avatar`
    });
},

Multiple File (With Dropzone)

Multiple file upload with async, dropzone and file list.

<div>
    <button id="product-gallery-dropzone" v-on:click="$upload.select('product-gallery')" :disabled="$upload.meta('product-gallery').state === 'sending'">
        <span v-show="$upload.meta('product-gallery').state === 'sending'">Uploading...</span>
        <span v-show="!$upload.meta('product-gallery').state === 'sending'">Select Photos</span>
    </button>

    <button v-on:click="$upload.reset('product-gallery')" :disabled="$upload.meta('product-gallery').state === 'sending'">
        Clear
    </button>
</div>

<div class="progress">
    <div class="progress-bar" :style="'width: ' + $upload.meta('product-gallery').percentComplete + '%;'">
        {{ $upload.meta('product-gallery').percentComplete }}% Complete
    </div>
</div>

<div v-if="$upload.errors('product-gallery').length" class="text-danger">
    {{ $upload.errors('product-gallery')[0].message }}
</div>

<div>
    <div v-if="!$upload.files('product-gallery').all.length">
        No uploads here yet.
    </div>

    <div v-for="file in $upload.files('product-gallery').progress">
        <div>
            {{ file.name }}
        </div>

        <div class="progress">
            <div class="progress-bar" :style="'width: ' + file.percentComplete + '%;'">
                {{ file.percentComplete }}%
            </div>
        </div>
    </div>

    <div v-for="file in $upload.files('product-gallery').queue">
        <div>
            {{ file.name }}
            <br/>
            Queued for upload
        </div>
    </div>

    <div v-for="file in $upload.files('product-gallery').success">
        {{ file.name }}
        <br/>
        Uploaded successfully.
    </div>

    <div v-for="file in $upload.files('product-gallery').error">
        {{ file.name }}
        <br/>
        {{ file.errors[0].msg }}
    </div>
</div>
created() {
    this.$upload.on('product-gallery', {
        maxFilesSelect: 20,
        dropzoneId: 'product-gallery-dropzone',
        multiple: true,
        onStart() {
             this.$toggle.show('product:media:uploads');
        },
        onSuccess(res) {
            this.product.gallery.push(res.data.data);
        },
        onEnd() {
            this.$msgbag.success('File upload complete.');
        }
    });
},

mounted() {
    this.$upload.option('product-gallery', {
        url: 'products/' + this.product.id + '/gallery'
    });
},

beforeDestroy() {
    this.$upload.off('product-gallery');
},

About

A simple, light weight and intuitive upload control for Vue.js.


Languages

Language:JavaScript 100.0%