Как ограничить загрузку файлов в dropzone.js?

#ruby-on-rails #dropzone.js #stimulusjs

Вопрос:

У меня есть приложение ruby on rails со стимулом.js и dropzone.js для загрузки вложения. Теперь существует ограничение на загрузку одного файла, но это позволяет загружать более одного файла и просто выводит на них сообщение об ошибке. Мне нужно, чтобы было невозможно загрузить более одного файла, и если после этого пользователь попытается загрузить другой, произойдет замена.

dropzone_controller.js

 import Dropzone from "dropzone"; import { Controller } from "stimulus"; import { DirectUpload } from "@rails/activestorage"; import {  getMetaValue,  toArray,  findElement,  removeElement,  insertAfter } from "helpers";  export default class extends Controller {  static targets = ["input"];   connect() {  this.dropZone = createDropZone(this);  this.hideFileInput();  this.bindEvents();  Dropzone.autoDiscover = false; // necessary quirk for Dropzone error in console  }   // Private  hideFileInput() {  this.inputTarget.disabled = true;  this.inputTarget.style.display = "none";  }   bindEvents() {  this.dropZone.on("addedfile", file =gt; {  setTimeout(() =gt; {  file.accepted amp;amp; createDirectUploadController(this, file).start();  }, 500);  });   this.dropZone.on("removedfile", file =gt; {  file.controller amp;amp; removeElement(file.controller.hiddenInput);  });   this.dropZone.on("canceled", file =gt; {  file.controller amp;amp; file.controller.xhr.abort();  });  }   get headers() {  return { "X-CSRF-Token": getMetaValue("csrf-token") };  }   get url() {  return this.inputTarget.getAttribute("data-direct-upload-url");  }   get maxFiles() {  return this.data.get("maxFiles") || 1;  }   get maxFileSize() {  return this.data.get("maxFileSize") || 256;  }   get acceptedFiles() {  return this.data.get("acceptedFiles");  }   get addRemoveLinks() {  return this.data.get("addRemoveLinks") || true;  } }  class DirectUploadController {  constructor(source, file) {  this.directUpload = createDirectUpload(file, source.url, this);  this.source = source;  this.file = file;  }   start() {  this.file.controller = this;  this.hiddenInput = this.createHiddenInput();  this.directUpload.create((error, attributes) =gt; {  if (error) {  removeElement(this.hiddenInput);  this.emitDropzoneError(error);  } else {  this.hiddenInput.value = attributes.signed_id;  this.emitDropzoneSuccess();  }  });  }   createHiddenInput() {  const input = document.createElement("input");  input.type = "hidden";  input.name = this.source.inputTarget.name;  insertAfter(input, this.source.inputTarget);  return input;  }   directUploadWillStoreFileWithXHR(xhr) {  this.bindProgressEvent(xhr);  this.emitDropzoneUploading();  }   bindProgressEvent(xhr) {  this.xhr = xhr;  this.xhr.upload.addEventListener("progress", event =gt;  this.uploadRequestDidProgress(event)  );  }   uploadRequestDidProgress(event) {  const element = this.source.element;  const progress = (event.loaded / event.total) * 100;  findElement(  this.file.previewTemplate,  ".dz-upload"  ).style.width = `${progress}%`;  }   emitDropzoneUploading() {  this.file.status = Dropzone.UPLOADING;  this.source.dropZone.emit("processing", this.file);  }   emitDropzoneError(error) {  this.file.status = Dropzone.ERROR;  this.source.dropZone.emit("error", this.file, error);  this.source.dropZone.emit("complete", this.file);  }   emitDropzoneSuccess() {  this.file.status = Dropzone.SUCCESS;  this.source.dropZone.emit("success", this.file);  this.source.dropZone.emit("complete", this.file);  } }  function createDirectUploadController(source, file) {  return new DirectUploadController(source, file); }  function createDirectUpload(file, url, controller) {  return new DirectUpload(file, url, controller); }  function createDropZone(controller) {  return new Dropzone(controller.element, {  url: controller.url,  headers: controller.headers,  maxFiles: controller.maxFiles,  maxFilesize: controller.maxFileSize,  acceptedFiles: controller.acceptedFiles,  addRemoveLinks: controller.addRemoveLinks,  autoQueue: false  }); }  

_form.html.erb

 lt;div data-lite-visibility-target="dynamic" class="space-y-8 lt;%= @automate_task_report.attachment.present? ? '' : "hidden" %gt;" gt;  lt;div class="form-group inverted"gt;  lt;%= form.label :attachment, "Upload test execution results", class: "form-label" %gt;  lt;button type="button" class="dropzone dropzone-default dz-clickable form-control form-file form-file-btn" data-controller="dropzone" data-dropzone-max-file-size="10" data-dropzone-max-files="1" data-dropzone-accepted-files=".xml,.html,.jpg,.jpeg,.png,.gif"gt;  lt;%= form.file_field :attachment, direct_upload: true, data: { target: 'dropzone.input' } %gt;  lt;div class="dropzone-msg dz-message needsclick flex m-0"gt;  lt;% if @automate_task_report.attachment.attached? %gt;  lt;%= form.hidden_field :attachment, value: @automate_task_report.attachment.signed_id %gt;  lt;div class="mx-5 attachment vertical"gt;  lt;%= link_to @automate_task_report.attachment, target: "_blank", class:"attachment-thumb" do %gt;  lt;%= image_tag(@automate_task_report.attachment) %gt;  lt;% end %gt;  lt;%= link_to @automate_task_report.attachment.filename.to_s, @automate_task_report.attachment, target: "_blank", class:"attachment-name" %gt;  lt;%= link_to @automate_task_report.attachment, download: @automate_task_report.attachment, class:"btn btn-primary attachment-btn" do %gt;  lt;span class="icon text-icon-default icon-download"gt;lt;/spangt;  lt;% end %gt;  lt;/divgt;  lt;% end %gt;  lt;span class="icon text-icon-lg icon-file-image-plus-lg mr-3"gt;lt;/spangt;  lt;div class="text-left mt-0"gt;  lt;pgt;Upload a file or drag and droplt;/pgt;  lt;p class="text-xs"gt;XML, HTML, PNG, JPG, GIF up to 10MBlt;/pgt;  lt;/divgt;  lt;/divgt;  lt;/buttongt;  lt;/divgt;  lt;/divgt;  lt;/divgt;  lt;/divgt;  

Я уже пробовал такие вещи, как

 = {  maxFiles: 1 };  

но у меня это не сработало. Как я могу достичь ожидаемого результата?

Ответ №1:

Используйте обратный вызов «принять», чтобы проверить максимальное количество файлов:

 accept: function(file, done) {  if (/* do a check here */) {  done(error message);  // File is cancel.  file.status = Dropzone.CANCELED;  } }  

ключевым моментом здесь является изменение статуса файла на отменено, чтобы сообщить об этом dropzone