Usuwanie załączników do uploadowania.

0

Sprawa jak w temacie. Potrzebuje mieć uploader który potrafiłby usunąć załączoną jakby informację o pliku który ma być dopiero uploadowany.

0

Znaczy chodzi ci o ten przycisk "cancel"?
Ze względów bezpieczeństwa JS nie bardzo może manipulować na <input type="file">, ale może już wydobyć z niego informację, a później skopiować ją do innego pola. A z tym innym polem możesz już sobie robić co chcesz, a później przy próbie wysłania odpalasz skrypt, który sprawdza jego zawartość i zależnie od stanu, wysyła lub nie wysyła.

0

@tymek42: odpowiadaj w postach na temat.

Twoja tablica files, to nic innego, jak wartość pola zawierającego pliki. No, może nie do końca wartość. Pole <input type="file" multiple> ma właściwość files. Ta właściwość, to obiekt FileList. Niestety póki co jest on readonly, więc nie możesz usunąć tego pliku. Można to obejść robiąc coś takiego jak poniżej. Czyli sam zarządzasz tablicą plików, a przy wysyłaniu na serwer manualnie ją składasz, a nie używasz wartości pola do uploadowania plików.

JSFiddle

class Uploader {
  constructor(config) {
    this.url = config.url;
    this.filesContainer = config.filesContainer;
    this.uploader = config.uploader;
    this.previewTemplate = config.previewTemplate;

    this.files = [];

    this.handleUpload = this.handleUpload.bind(this);
    this.handleRemove = this.handleRemove.bind(this);

    this.bindEvents();
  }

  bindEvents() {
    this.uploader.addEventListener('change', this.handleUpload);
  }

  handleUpload(e) {
    this.files = [...this.uploader.files];
    this.renderFiles();
  }

  handleRemove(e, file) {
    this.files = this.files.filter(f => f !== file);
    this.renderFiles();
  }

  renderFiles() {
    this.filesContainer.querySelectorAll('img')
      .forEach(node => node.remove());

    this.files
      .map(file => this.previewTemplate(this, file))
      .forEach(file => this.filesContainer.appendChild(file));
  }

  upload() {
    const body = new FormData();

    this.files.forEach(file => body.append('files[]', file));

    return fetch(this.url, {
      body: body,
      method: 'post',
    });
  }
}

const form = document.querySelector('form');
const uploader = new Uploader({
  url: form.action,
  filesContainer: document.querySelector('#files-container'),
  uploader: document.querySelector('#uploader'),
  previewTemplate: (uploader, file) => {
    const preview = document.createElement('img');
    preview.addEventListener('click', e => uploader.handleRemove(e, file));

    const reader = new FileReader();
    reader.onload = () => preview.src = reader.result;
    reader.readAsDataURL(file);

    return preview;
  }
});

form.addEventListener('submit', e => {
  e.preventDefault();

  uploader.upload().then(resp => resp.json()).then(resp => console.log(resp));
});
1

@Freja Draco: Pooooosty!

  1. Używamy zwykłego pola, które pozwala nam załadować pliki. Wpinamy się w zdarzenie change i dzięki temu mamy dostęp do plików, które załadował użytkownik.
  2. Ponieważ pobrana tablica plików jest tylko do odczytu, a my chcemy móc usuwać coś z niej, to pliki przetrzymujemy we własnej tablicy.
this.files = [...this.uploader.files];
  1. Teraz możemy dowolnie dodawać i usuwać elementy z tej tablicy. Ale do usuwania potrzebujemy jakiegoś mechanizmu. Musimy najpierw te pliki wyświetlić. Do tego używamy funkcji renderFiles. Ona używa funkcji dostarczonej przez klienta naszej klasy, do stworzenia elementów previewTemplate, co daje nam większą reużywalność, bo każdy może sobie wyświetlić plik do podglądu tak jak mu się będzie podobało.
  2. Wewnątrz previewTemplate nie ma żadnej magii. Tak po prostu ładuje się plik, żeby go wyświetlić.
  3. W tej samej funkcji previewTemplate dodajemy zdarzenie click, na którym to usuwamy nasz kliknięty plik z tablicy files. Do tego używamy API dostarczonego przez naszą klasę Uploader.
  4. Jeżeli chcemy wysłać pliki na serwer, to wywołujemy kolejną funkcję z naszego API, jakie dostarcza nam klasa Uploader. Wewnątrz funkcji upload też nie ma żadnej magii. Po prostu używamy FormData, pakujemy pliki do środka i wysyłamy na serwer.
0

@Desu: Dobra, to może inaczej. Pomijając szczegóły skryptów, skupmy się na efekcie.

Potrafię sobie wyobrazić sytuację, w której:

  • tworzymy kopię oryginalnej tablicy plików,
  • modyfikujemy ją i ładujemy do kolejnego pola formularza,
  • formularzem przesyłamy `wszystkie' pierwotnie zaznaczone pliki, ale zmodyfikowana tablica plików mówi serwerowi, które z nich ma obsłużyć i załadować, a które zignorować.
    I zakładam, że tak właśnie działa powyższy skrypt.

Czy też może jest jednak jakaś metoda na usunięcie plików z formularza jeszcze przed wysłaniem i w efekcie nieprzesyłanie ich?

1

Przesyłasz tylko pliki, które masz w swojej tablicy. Pliki z pola, którego używasz do załadowania plików ignorujesz. Jeżeli używasz mojej metody, czyli ajax, to nie musisz nic z nimi robić. Na serwer pójdą tylko pliki z Twojej tablicy, z której możesz dowolnie usuwać. Jeżeli wysyłasz formularz normalnie, to pole do załadowania plików możesz albo usunąć, albo umieścić je poza formularzem, co spowoduje, ze załadowane pierwotnie pliki w ogóle nie zostaną wysłane. Innej metody nie ma, ponieważ nie możesz zmodyfikować zawartości pola do załadowania plików, trzeba kombinować. Jedyny znany mi sposób, to ten który przedstawiłem. Tak działają wszystkie biblioteki do uploadowania plików, ja stworzyłem minimum konieczne, bez wodotrysków, żebyś zobaczył jak to działa pod spodem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1