Uploader

‹ Back
Warning: IE8/9 not supported. Requires Koi's asset models (Image and Document).

Example uploader

Here is an example uploader in demo mode. It will simulate an upload but won't actually save anywhere.

This is a hint message for the image uploader

<%= render "form_field_uploader", { f: f, attr: :banner_image } -%>

By default the uploader assumes a 1:1 aspect ratio for your image, however you can change this by passing in ratio:.

This is a hint message for the image uploader

<%= render "form_field_uploader", { f: f, attr: :banner_image, ratio: "2/1" } -%>

Cropping

You can add the crop tool by simply adding croppable: "true" to your partial include:

This is a hint message for the image uploader

<%= render "form_field_uploader", { f: f, attr: :banner_image, croppable: "true" } -%>

Aspect ratio changes can be set alongside croppability:

This is a hint message for the image uploader

<%= render "form_field_uploader", { f: f, attr: :banner_image, ratio: "2/1", croppable: "true" } -%>

This is a hint message for the image uploader

<%= render "form_field_uploader", { f: f, attr: :banner_image, ratio: "1/2", croppable: "true" } -%>

Existing images

The uploader supports existing images by showing the thumbnail (and crop if available) with no extra logic needed in your markup. Simply include the partial as normal and if an image already exists it will show it.

This is a hint message for the image uploader

<%= render "form_field_uploader", { f: f, attr: :banner_image, croppable: true } -%>

Document Uploads

The uploader will switch to "file" mode (rather than image mode) if the file types include "pdf", "xls", "xlsx", "doc", "docx".

These requirements can be updated in the form_field_uploader partial.

This is a hint message for the image uploader

<%= render "form_field_uploader", { f: f, attr: :banner_image, types: "pdf, xls, xlsx, doc, docx"} -%>

Behind the scenes

There are two hidden fields (exposed here) that track the asset ID when the image is uploaded and the crop string if croppable.

The image id is emptied when the image is removed.

The crop string only saves when a crop is made. The crop string is emptied when the image is removed.

You can see the fields updating here as you add, remove and crop images.

This is a hint message for the image uploader


Events and callbacks

Change the state of the uploader by triggering uploader:set-state:[state]

eg. $(".my-uploader").trigger("uploader:set-state:saving");

The available states are:

  • Idle (no image)
  • Uploading
  • Saving
  • Uploaded
  • Error

Note: setting states does not destroy data. If you change the state from uploaded to idle, the image and fields will still be filled in. This is purely presentational.

There are several events that fire at certain times during the upload process that you can hook in to by adding on() event handlers to your field. For example:

$(".my-field").on("uploader:after-upload", function(e,$uploader,$dropZone,$cropStringField,$hiddenField){ 
  alert("uploaded!") 
}

The list of events are:

  • on("uploader:init", function() {})
  • on("uploader:after-upload", function(e,$uploader,$dropZone,$cropStringField,$hiddenField) {})
  • on("uploader:image-removed", function() {})
  • on("uploader:progress-bar-updated", function() {})
  • on("uploader:state-changed", function(event,state) {})
  • on("uploader:crop-set", function(event,cropValue,$cropField) {})
  • on("uploader:upload-cancelled", function() {})

There are also some action events you can trigger on the field:

  • uploader:update-thumbnail
  • uploader:close-crop-modal

This is a hint message for the image uploader


  
<div data-uploader-callbacks>
  <%= render "form_field_uploader", { f: f, attr: :banner_image } -%>
  <pre data-uploader-tracker></pre>
</div>
<script>
  $(document).on("ornament:refresh", function(){
    var $callbacksContainer = $("[data-uploader-callbacks]");
    var $callbackUploader = $callbacksContainer.find("[data-file-uploader]");
    var $callbackTracker = $callbacksContainer.find("[data-uploader-tracker]");

    $callbackUploader.on("uploader:init", function(){
      $callbackTracker.append("Uploader initialised<br />");
    }).on("uploader:after-upload", function(e, $uploader, $dropZone, $cropStringField, $hiddenField) {
      $callbackTracker.append("Upload successful" + "<br />");
    }).on("uploader:image-removed", function(e) {
      $callbackTracker.append("Image was removed" + "<br />");
    }).on("uploader:progress-bar-updated", function(e, value) {
      $callbackTracker.append("Progress was changed to " + value + "<br />");
    }).on("uploader:state-changed", function(e, state) {
      $callbackTracker.append("State was changed to: " + state + "<br />");
    }).on("uploader:crop-set", function(e, cropValue, $cropField) {
      $callbackTracker.append("Crop set to: " + cropValue + "<br />");
    }).on("uploader:modal-opened", function(e){
      $callbackTracker.append("Crop modal opened<br />");
    }).on("uploader:upload-cancelled", function(e){
      $callbackTracker.append("Upload was cancelled<br />");
    });
  });
</script>

Setting up your model

All uploads are passed through to the Asset model so instead of storing the image as a dragonfly object aginst the model, all you store is an integer field for the asset id.

Assuming you want to create an uploader for "banner image", you'll need a migration to add banner_image_id:integer to your model:

rails generate migration AddBannerImageIdToModel banner_image_id:integer

If you want to be able to crop your banner image, you'll also need a crop_string, in which case you would change your migration to add a second field as well:

rails generate migration AddBannerImageToModel banner_image_id:integer banner_image_crop:string

Then in your form you want to render the uploader partial:

<%= render "form_field_uploader", { f: f, attr: :cover_image } -%>

If you want to enable cropping for the field, simply add a ratio value to the crop_ratio attribute:

<%= render "form_field_uploader", { f: f, attr: :cover_image, crop_ratio: "1/1" } -%>

Open up your model and add some basic helper functions for the view.

def banner_image_asset
  Asset.find(banner_image_id).data
end

def banner_image
  if banner_image_crop.blank?
    banner_image_asset
  else
    banner_image_asset.thumb(banner_image_crop)
  end
end

This will set up a banner_image method that will look to see if there's a crop available, if not it just uses the original image that was uploaded.

Now in your view you can simply call <%= @my_model.banner_image.url -%> to get the cropped version of the image.