2016-01-11 14 views
16

Iam scrivere uno script che carica i file tramite Drag and Drop utilizzando jQuery che legge il file su goccia e lo aggiunge a una serie di file in questo modo:

var files = []; 

$(document).ready(function() { 
    jQuery.fn.dropbox = function(config) { 
     var dragging = 0; 
     var dragEnter = function(e) { 
      e.stopPropagation(); 
      e.preventDefault(); 
      dragging++; 
      $(".external-drop-indicator").fadeIn(); 
      $(".toast.toast-success").fadeIn().css("display", "inline-block");; 
      return false; 
     }; 
     var dragOver = function(e) { 
      e.stopPropagation(); 
      e.preventDefault(); 
      return false; 
     }; 
     var dragLeave = function(e) { 
      e.stopPropagation(); 
      e.preventDefault(); 
      dragging--; 
      if(dragging === 0) { 
       $(".external-drop-indicator").fadeOut(); 
       $(".toast.toast-success").fadeOut(); 
      } 
      return false; 
     }; 
     var drop = function(e) { 
      var dt = e.dataTransfer; 
      var files_upload = dt.files; 

      e.stopPropagation(); 
      e.preventDefault(); 

      if(files_upload && files_upload.length > 0 && config.onDrop !== undefined) { 
       files.push(files_upload); 
       config.onDrop(files_upload); 
      } 

      $(".external-drop-indicator").fadeOut(); 
      $(".toast.toast-success").fadeOut(); 

     }; 
     var applyDropbox = function(dropbox) { 
      dropbox.addEventListener('dragenter', dragEnter, false); 
      dropbox.addEventListener('dragover', dragOver, false); 
      dropbox.addEventListener('dragleave', dragLeave, false); 
      dropbox.addEventListener('drop', drop, false); 
     }; 
     return this.each(function() { 
      applyDropbox(this); 
     }); 
    }; 
}); 

In sintesi, ciò che fa è aggiungere una funzione jQuery estesa per abilitare il trascinamento su un determinato elemento del sito Web in cui viene applicata la funzione.

Poi applicare la funzionalità estesa al corpo per poter abilitare il file funzionalità drag and drop in questo modo:

$(document).ready(function() { 
    $('body').dropbox({ 
     onDrop: function(f) { 
      $(f).each(function(idx, data) { 
       var file_name = data.name; 
       var extension = file_name.split('.'); 
       file_name = extension[0]; 
       extension = extension[1]; 
       if(extension == 'pdf' || extension == 'xls') { 
        showAjaxModal(base_url + 'index.php?modal/popup/file_create/' + folder_id + '/' + extension + '/' + file_name); 
       } else { 
        $(".upload-area").append('<div class="alert alert-danger" style="display:inline-block;width:480px;"><strong>Error!</strong> File type is incorrect.</div>'); 
       } 
      }); 
     } 
    }); 
}); 

In sintesi ciò che fa è aggiunge la funzionalità drag and drop per il corpo e quando un file viene rilasciato rileva l'estensione del file dividendo il nome e l'estensione, in modo da poter verificare che l'estensione del file che è stato rilasciato sia corretta. Quindi procede a mostrare una modale per riempire le informazioni sul file che viene caricato per una successiva presentazione, se l'estensione del file è corretta.

Poi procedere a riempire le informazioni del file utilizzando la funzione di CodeIgniter "Form_Open()" quando i pops modale in questo modo:

<?php echo form_open(base_url() . 'index.php?client/file/create/' . $param2, array('class' => 'form-horizontal form-groups-bordered validate ajax-upload', 'enctype' => 'multipart/form-data')); ?> 

    <div class="col-md-4 file-info"> 
     <div class="icon-<?=($param3 == 'pdf' ? 'pdf' : 'document')?>"></div> 
     <p> 
      <?php echo $param4;?> 
     </p> 
    </div> 

    <div class="col-md-8 new-file"> 

     <div class="form-group"> 
      <div class="col-sm-12"> 
       <div class="input-group"> 
        <input type="text" class="form-control" name="tags" data-validate="required" data-message-required="Field is required" placeholder="File tags" value="" autofocus> 
       </div> 
      </div> 
     </div> 

     <div class="form-group"> 
      <div class="col-sm-12"> 
       <div class="input-group"> 
        <input type="text" class="form-control" name="name" data-validate="required" data-message-required="Field is required" placeholder="File name" value="" autofocus> 
       </div> 
      </div> 
     </div> 

     <div class="form-group"> 
      <div class="col-sm-12"> 
       <div class="input-group"> 
        <textarea rows="5" class="form-control" name="description" data-validate="required" data-message-required="Field is required" placeholder="File description" value="" autofocus></textarea> 
       </div> 
      </div> 
     </div> 

    </div> 

    <div class="form-group"> 
     <div class="col-sm-offset-4 col-sm-7"> 
      <button type="submit" class="btn btn-info" id="submit-button">Upload</button> 
      <span id="preloader-form"></span> 
     </div> 
    </div> 

<?php echo form_close(); ?> 

Questo crea sostanzialmente una forma che poi verrà inviato tramite Ajax.

Ora procedere per gestire la presentazione file tramite jQuery per le informazioni da inviare con il file oi file che vengono caricato in questo modo:

$(document).ready(function(e) { 
    $('.ajax-upload').submit(function(e) { 
     e.preventDefault(); 

     var $elm = $(this); 

     var fd = new FormData(); 

     for(var i = 0; i < files.length; i++) { 
      fd.append("file_" + i, files[i]); 
     } 

     var form_data = $(".ajax-upload").serializeArray(); 

     $.each(form_data, function(key, input) { 
      fd.append(input.name, input.value); 
     }); 

     var opts = { 
      url: $elm.attr('action'), 
      data: fd, 
      cache: false, 
      contentType: false, 
      processData: false, 
      type: 'POST', 
      beforeSend: uValidate, 
      success: showResponse 
     }; 

     if(fd.fake) { 
      opts.xhr = function() { 
       var xhr = jQuery.ajaxSettings.xhr(); 
       xhr.send = xhr.sendAsBinary; 
       return xhr; 
      } 
      opts.contentType = "multipart/form-data; boundary=" + fd.boundary; 
      opts.data = fd.toString(); 
     } 

     jQuery.ajax(opts); 

     return false; 
    }); 
}); 

In sostanza l'azione modulo predefinito viene sovrascritto e le file che sono stati inviati sul blocco di codice precedente per la funzionalità di trascinamento della selezione sono ora accodati a formData che in seguito verrà aggiunto ai dati del modulo presenti nel modulo che invio. Quindi il formData viene inviato tramite una chiamata AJAX.

Ora il controller assomiglia a questo, gestisce la chiamata AJAX e poi esegue il metodo di caricamento dei file sul modello in questo modo:

function file($param1 = '', $param2 = '', $param3 = 0) { 
    if ($this->session->userdata('client_login') != 1) { 
     $this->session->set_userdata('last_page', current_url()); 
     redirect(base_url(), 'refresh'); 
    } 

    if ($param1 == 'create') 
     $this->crud_model->create_file($param2); 

    if ($param1 == 'edit') 
     $this->crud_model->update_file($param2); 

    if ($param1 == 'delete') 
     $this->crud_model->delete_file($param2, $param3); 

    $page_data['page_name'] = 'files'; 
    $page_data['page_title'] = 'Files List'; 
    $page_data['folder_id'] = $param3; 
    $this->load->view('backend/index', $page_data); 
} 

Ecco il metodo dei modelli:

function create_file($folder_id) { 
    $data['name']   = $this->input->post('name'); 
    $data['tags']   = $this->input->post('tags'); 
    $data['description'] = $this->input->post('description'); 
    $data['type']   = 'file'; 
    $data['folder_id'] = $folder_id; 
    $data['client_id'] = $this->session->userdata('login_user_id'); 

    $config['upload_path'] = 'uploads/tmp/'; 
    $config['allowed_types'] = '*'; 
    $config['max_size'] = '100'; 

    $this->load->library('upload'); 
    $this->upload->initialize($config); 

    var_dump($_FILES); 
    die(); 

    foreach($_FILES as $field => $file) 
    { 
     //var_dump($_FILES); die();     
     // No problems with the file 
     if($file['error'] == 0) 
     { 
      // So lets upload 
      if ($this->upload->do_upload($field)) 
      { 
       $data = $this->upload->data(); 
       echo $data['full_path']; 
      } 
      else 
      { 
       $errors = $this->upload->display_errors(); 
       var_dump($errors); 
      } 
     } 
    } 

    $this->db->insert('client_files' , $data); 
} 

Così in pratica, ciò che accade è che l'array $ _FILES è vuoto e il file non viene caricato.

la "richiesta Payload" come visto su Developer Tools di Chrome si presenta così:

------WebKitFormBoundaryvVAxgIQd6qU8BtkF 
Content-Disposition: form-data; name="file_0" 

[object FileList] 
------WebKitFormBoundaryvVAxgIQd6qU8BtkF 
Content-Disposition: form-data; name="tags" 

bsd 
------WebKitFormBoundaryvVAxgIQd6qU8BtkF 
Content-Disposition: form-data; name="name" 

asd 
------WebKitFormBoundaryvVAxgIQd6qU8BtkF 
Content-Disposition: form-data; name="description" 

asd 

E la risposta che ricevo dalla var_dump() sul modello è la seguente:

array(0) { 
} 

Ho provato la soluzione su questa domanda: Sending multipart/formdata with jQuery.ajax Ma nessuna fortuna finora.

Qualche idea su cosa sto facendo male e su come risolvere questo problema? Grazie.

+0

Stai inviando 'base_url + 'index.php? Modal/popup/file_create /' + folder_id + '/' + extension + '/' + file_name' da AJAX, ma il lato server si aspetta solo' function create_file ($ folder_id) { '. Visualizza i percorsi e/o modifica il metodo di configurazione per accettare la quantità corretta di parametri. – Tpojka

+0

@Tpojka L'url è solo per il modale, l'effettivo 'create_file ($ folder_id) ... 'viene chiamato quando il modulo viene inviato. Non ha nulla a che fare con il caricamento del file vero e proprio. – Joscplan

risposta

7

Il problema qui è che sto inviando la serie di file invece di singoli file sul chiamata AJAX, in particolare in questa parte del codice:

for(var i = 0; i < files.length; i++) { 
    fd.append("file_" + i, files[i]); 
} 

La soluzione era quella di aggiungere file per file alla formdata invece che la serie di file, qualcosa di simile:

for(var i = 0; i < files[0].length; i++) { 
    fd.append("file_" + i, files[i]); 
} 

questo aggiungerà ogni singolo file della matrice file invece che la serie di file stesso e si risolve il problema.

In conclusione inviavo la serie di file invece di singoli file, la chiave di questo è stato il [object FileList] che la richiesta stava mostrando invece delle informazioni file, che ora fa una richiesta del genere:

Content-Disposition: form-data; name="file"; filename="exfile.pdf" 
Content-Type: application/pdf