How to set File objects and length property at FileList object where the files are also reflected at FormData object?

后端 未结 1 1266
栀梦
栀梦 2020-11-22 04:01

It is possible to set .files property of element to a FileList from for example a different

1条回答
  •  时光说笑
    2020-11-22 04:52

    Edit:

    As proven by OP, in one of their gist, there is actually a way to do it...

    The DataTransfer constructor (currently only supported by Blink, and FF >= 62), should create a mutable FileList (chrome currently always return a new FileList, but it doesn't really matter for us), accessible through the DataTransferItemList.

    If I'm not mistaken, this is currently the only specs-wise way to do it, but Firefox had a bug in their implementation of the ClipboardEvent constructor, where the same DataTransferItemList was and set to the mode read/write which allowed a workaround for FF < 62. I am not sure of my interpretation of the specs, but I believe it should not be accessible normally).

    So the way guest271314 found to set arbitrary files on a FileList is as follow:

    const dT = new ClipboardEvent('').clipboardData || // Firefox < 62 workaround exploiting https://bugzilla.mozilla.org/show_bug.cgi?id=1422655
      new DataTransfer(); // specs compliant (as of March 2018 only Chrome)
    dT.items.add(new File(['foo'], 'programmatically_created.txt'));
    inp.files = dT.files;

    This discovery has lead to this new Proposal to make FileList objects mutable by default, since there is no point anymore to not do it.


    Previous (outdated) answer

    You can't. FileList objects cannot be modified by scripts*.

    You can only exchange the FileList of an input to an other FileList, but you can't modify it*.
    (*Except for emptying with input.value = null).

    And you can't either create FileList from scratch, only DataTransfer objects which cannot be created either, and input[type=file] will create such objects.

    To show you that even when setting an input[type=file] FileList to an other input's one no new FileList is created:

    var off = inp.cloneNode(); // an offscreen input
    
    inp.onchange = e => {
      console.log('is same before', inp.files === off.files);
      off.files = inp.files; // now 'off' does have the same FileList as 'inp'
      console.log('is same after', inp.files === off.files);
      console.log('offscreen input FileList', off.files);
      console.log('resetting the offscreen input');
      off.value = null;
      console.log('offscreen input FileList', off.files);         
      console.log('inscreen input FileList', inp.files);
    }

    Oh And I almost forgot the FormData part, that I don't really understood to say the truth...

    So if I got it ok, all you need is simply FormData.append():

    var fd = new FormData();
    
    fd.append("files[]", new Blob(['a']), 'a.txt');
    fd.append("files[]", new Blob(['b']), 'b.txt');
    
    for(let pair of fd.entries()) {
       console.log(pair[0], pair[1]); 
    }

    0 讨论(0)
提交回复
热议问题