2014-09-10 2 views
0

Я разработал загрузчик файлов ajax, и он отлично работает, если один экземпляр находится на странице. Я пытаюсь преобразовать его, чтобы разрешить несколько экземпляров, и он почти работает, EXCEPT, когда я загружаю несколько файлов в одной форме, он загружает первый файл в порядке, но затем для всех последующих файлов по какой-либо причине он указывает вперед к следующему файловому считывателю из экземпляра второй формы. Если я загружу, используя последний (второй) экземпляр формы загрузки, вы сможете загрузить несколько файлов. Но если я попытаюсь загрузить первый экземпляр, он загрузит первый файл, но все последующие файлы будут отправлены на пустой входной файл из второго экземпляра. Я не понимаю, почему. Я использую уникальные имена идентификаторов в форме загрузки и ссылаюсь на этот уникальный идентификатор во всех функциях javascript. Я попытаюсь включить все необходимые биты кода ниже.Несколько экземпляров Ajax Uploader на той же странице

Формы генерируются PHP. Php var $uid - это случайно созданный уникальный идентификатор, который я использую во всем. Во-первых, инициализация функции загрузки выводится на страницу в <script> тэгом:

'<script> '. 
    'jQuery(document).ready(function($){ '. 
     'var myup_'.$uid.' = new MyUp({ '. 
      'form_id: "myup_form_'.$uid.'", '. 
      'uid: '.$uid.', '. 
      'container: "'.$name.'", '. 
      'table: "'.$style.'", '. 
      'iconcolor: "'.$iconcolor.'", '. 
      'maxsize: '.$maxsize.', '. 
      'permitted: '.$permitted.', '. 
      'prohibited: '.$prohibited.', '. 
      'fixed: '.$fixedsetting.', '. 
      'pathcheck: "'.$pathcheck.'", '. 
      'uploader: '.$uploader.', '. 
      'loading: "'.my_url.'/lib/img/ajax.gif" '. 
     }); '. 
    '}); '. 
'</script>'; 

Очевидно, что все эти переменные для моих настроек определены ранее. С несколькими экземплярами на странице он правильно считывает настройки для каждого отдельного экземпляра. Они успешно отображаются с разными стилями, цветами значков, разрешениями типа файла, максимальными настройками размера файла и т. Д. Все это работает с несколькими экземплярами.

Теперь форма:

'<div class="myup_container" style="'.$inlinestyle.'">'. 
    '<form name="myup_form_'.$uid.'" id="myup_form_'.$uid.'" action="javascript:void(0);" enctype="multipart/form-data">'. 
     '<input type="hidden" id="upload-actionpath-'.$uid.'" value="'.$fixed.'" data-basename="'.$basename.'" data-start="'.$start.'" />'. 
     '<div class="myup_buttons_container" style="text-align:right;">'. 
      '<span class="myup_wrapper" style="text-align:left;">'. 
       '<input type="file" name="myup_files_'.$uid.'[]" id="myup_files_'.$uid.'" class="hidden_browse"'.$multiple.' />'. 
       '<span class="add_files">'.$addfiles.'</span>'. 
       '<span id="submit_upload_'.$uid.'">'.$uploadlabel.'</span>'. 
      '</span>'. 
     '</div>'. 
    '</form>'. 
    '<div id="myup_files_container_'.$uid.'" class="myup_files_container"></div>'. 
    '<span id="my_removedfiles_'.$uid.'" style="display:none;"></span>'. 
'</div>'; 

Так что это урезанный вариант. Экземпляр в теге скрипта, содержащий настройки и форму html, выводится по короткому коду. Таким образом, на нескольких коротких кодах на странице будут выводиться несколько экземпляров функции MyUp.

Вот что я надеюсь, все соответствующие биты яваскрипта функций (это долго, извините, но я удалил тонну материала):

jQuery(document).ready(function($) 
{ 
// throughout, the var fuid will refer 
// to the php var $uid from the html form and instance settings 

function myupRemove(id, filename, fuid) 
{ 
    // handle files the user removes from the input field 
    // before submitting the upload 
} 
function MyUp(config) 
{ 
    this.settings = config; 
    this.fuid = this.settings.uid; 
    this.file = ""; 
    this.browsed_files = []; 
    var self = this; 
    MyUp.prototype.myupDisplay = function(value) 
    { 
     this.file = value; 
     if(this.file.length > 0) 
     { 
      /* this is a really long bit of code 
      * that i'll spare you, but basically I iterate 
      * through all the files in the input field 
      * and put them dynamically into a table 
      * and drop the table onto the page 
      * so the user can rename them, remove them before upload, 
      * and then watch the status bar for each file as it uploads. 
      * This portion of the code works fine with multiple instances. 
      */ 
     } 
    } 
    // Create Unique ID 
    MyUp.prototype.uid = function(name) 
    { 
     // Here I generate a unique ID for each file, 
     // and prepend it with the Instance's unique id (i.e., this.fuid) 
     return this.fuid+'_'+name.replace(/[^a-z0-9\s]/gi, '_').replace(/[_\s]/g, '_'); 
    }   
    // Get File Extension 
    MyUp.prototype.ext = function(file, lowercase) 
    { 
     return (/[.]/.exec(file)) ? (lowercase ? /[^.]+$/.exec(file.toLowerCase()) : /[^.]+$/.exec(file)) : ''; 
    } 
    // Format File Size 
    MyUp.prototype.nicesize = function(fileSize) 
    { 
     // a bunch of code to format the file size then... 
     return niceSize; 
    } 
    // Attribute FileType Icons 
    MyUp.prototype.icon = function(icon_ext, color) 
    { 
     // a bunch of arrays to determine 
     // which file type icon to display in the table 
    } 
    //File Reader 
    MyUp.prototype.read = function(e) 
    { 
     if(e.target.files) 
     { 
      // references the myupDisplay function 
      // where I add the files to a table 
      self.myupDisplay(e.target.files); 
      self.browsed_files.push(e.target.files); 
     } 
    } 
    function addEvent(type, el, fn) 
    { 
     if(window.addEventListener) 
     { 
      el.addEventListener(type, fn, false); 
     } 
     else if(window.attachEvent) 
     { 
      var f = function() 
      { 
       fn.call(el, window.event); 
      };   
      el.attachEvent('on' + type, f) 
     } 
    } 
    // Collect File IDs and Initiate Upload for Submit 
    MyUp.prototype.starter = function() 
    { 
     if(window.File && window.FileReader && window.FileList && window.Blob) 
     { 

      var browsed_file_id = $("#"+this.settings.form_id).find("input[type='file']").eq(0).attr("id"); 
      document.getElementById(browsed_file_id).addEventListener('change', this.read, false); 
      document.getElementById('submit_upload_'+this.fuid).addEventListener('click', this.submit, true); 
     } 
     else alert(browser_cant_read_message); 
    } 
    // Begin Upload on Click 
    MyUp.prototype.submit = function() 
    { 
     self.begin(); 
    } 
    // Initiate Upload Iterator 
    MyUp.prototype.begin = function() 
    { 
     if(this.browsed_files.length > 0) 
     { 
      for(var k=0; k<this.browsed_files.length; k++) 
      { 
       var file = this.browsed_files[k]; 
       this.myupAjax(file,k); 
      } 
      this.browsed_files = []; 
     } 
     else alert(no_files_chosen_message); 
    } 
    // Ajax Upload 
    MyUp.prototype.myupAjax = function(file,i) 
    { 
     if(file[i]!== undefined) 
     { 
      var id = file_id = self.uid(file[i].name), 
       rawname = file[i].name.substr(0, file[i].name.lastIndexOf('.')) || file[i].name, 
       extension = self.ext(file[i].name, false), 
       browsed_file_id = $("#"+this.settings.form_id).find("input[type='file']").eq(0).attr("id"); 
       path = this.settings.fixed ? this.settings.fixed : String($('input#upload-actionpath-'+this.fuid).val()), 
       pathcheck = String(this.settings.pathcheck), 
       removed_file = $("#"+id).val(), 
       newname = String($('input#rename_upfile_id_'+id).val()), 
       new_name = newname === '' || newname === 'undefined' || newname === undefined ? file[i].name : newname+'.'+extension, 
       removed = this.settings.removed, 
       loading = this.settings.loading, 
       fixedchars = this.settings.fixed; 
      // if the file is removes, skip to the next file 
      if(removed_file !== '' && removed_file !== undefined && removed_file == id) self.myupAjax(file,i+1); 
      else 
      { 
       var myupData = new FormData(); 
       myupData.append('upload_file',file[i]); 
       myupData.append('upload_file_id',id); 
       myupData.append('max_file_size',this.settings.maxsize); 
       myupData.append('upload_path',path);  
       myupData.append('new_name',new_name); 
       myupData.append('extension',extension); 
       myupData.append('uploader',this.settings.uploader); 
       myupData.append('act','upload'); 
       myupData.append('nonce',myup.nonce);     
       $.ajax(
       { 
        type  : 'POST', 
        url   : myup.ajaxurl+'?action=myup-uploads', 
        data  : myupData, 
        id   : id, 
        fuid  : this.fuid, 
        new_name : new_name, 
        rawname  : rawname, 
        extension : extension, 
        path  : path, 
        pathcheck : pathcheck, 
        removed  : removed, 
        loading  : loading, 
        fixedchars : fixedchars, 
        cache  : false, 
        contentType : false, 
        processData : false, 
        beforeSend : function(xhr, settings) 
        { 
         // I added this alert because it shows me that when I'm using the first instance 
         // after the first file uploads, it starts looking to the file input field 
         // from the second instance 
         alert('path: '+settings.path+' pathcheck: '+settings.pathcheck); 

         // in here I do a bunch of security stuff before uploading 
        }, 
        xhr: function() 
        { 
         // my progress bar function here 
        }, 
        success : function(response) 
        { 
         setTimeout(function() 
         { 
          if(response.indexOf(id) != -1) 
          { 
           // do success stuff, like green checkmark, remove table row, etc. 
          } 
          else 
          { 
           // do failure stuff, like red x and error message 
          } 

          // AND HERE IS THE IMPORTANT PART 
          // THIS SAYS TO GO ON TO THE NEXT FILE IN THE ARRAY 
          // BUT WHEN USING THE FIRST INSTANCE 
          // IT SENDS US TO THE SECOND INSTANCE'S FILE READER 
          // if I'm uploading with the second form it's fine 
          if(i+1 < file.length) self.myupAjax(file,i+1); 
         },500); 
        } 
       }); 
      } 
     } 
    } 
    this.starter(); 
} 
window.MyUp = MyUp; 
window.myupRemove = myupRemove; 
}); 

Примечание комментарий блок к концу указанного выше кода фрагмент, где комментарий находится во всех шапках. Вот где он завершает загрузку ajax для файла, а затем отправляет нас назад, чтобы сделать следующий.

Так что, в основном, повторять, если у меня есть две формы на странице, когда я использую вторую форму, все работает нормально. Когда я использую первую форму, первый файл будет загружаться отлично, но затем он начинает искать следующий файл в поле ввода из второго экземпляра.

Есть ли относительно простое решение для этого?

+0

Вы можете указать страницу с примером. – 19greg96

+0

Вы говорите, что он работает так, как должен, когда вы загружаете второй экземпляр. Как насчет того, когда у вас есть, скажем, 3 или более экземпляра? Все последующие (от второго) работают? – melancia

+1

Мне кажется, что когда вы объявляете 'self' здесь:' var self = this; 'он сохраняет ссылку на последний экземпляр, поэтому он будет работать нормально только с последним, независимо от того, является ли он вторым, третий и т. д., экземпляр. – melancia

ответ

0

Ну, я не мог заставить его работать так, как предложил Алекс Гёшев (недостаток с моей стороны, без сомнения), поэтому я решил полностью избавиться от маршрута объекта/прототипа. Вместо создания экземпляров в форме я объявляю переменную MyUpConfig в глобальном пространстве как пустой массив. Затем в каждой форме html добавляется MyUpConfig['.$uid.'] =, а затем мой массив настроек.

Затем в файле js я связываю входные данные каждого файла и отправляю события на уникальный идентификатор и сохраняю данные файла каждого входного поля в таком массиве, как это: TheFiles[uid] = files. Поэтому, когда происходит отправка отправки, он получает uid из элемента кнопки загрузки и только пытается загрузить файлы, хранящиеся в массиве, соответствующие этому уникальному идентификатору.

Теперь у меня есть работа с несколькими форматами загрузки на одной странице. Каждый из них может работать одновременно без помех.

0

В опубликованном коде функция-конструктор объявляет все прототипы. Это заставляет их переопределяться каждый раз, когда создается новый объект MyUp, и они будут использовать конфигурацию из последней.

function MyUp(config) { 
    /// ... 
    var self = this; 
    MyUp.prototype.foo = function() { 
     // use `self` 
    }; 
} 

Вместо этого, вы должны объявить методы разы и использовать this ссылки, чтобы получить все присоединенные объекты:

function MyUp(config) { 
    /// ... 
} 
MyUp.prototype.foo = function() { 
    // use `this` 
}; 

Если вам нужны статические члены для класса (методы или переменные, которые не являются прикрепленные к любому экземпляру), вы можете объявить их как поля функции, если они должны использоваться публично - MyUp.begin = function() {}.Или внутри модуля, если они являются частными:

(function() { 
    var uploadsInProgress = 0; 

    // declare MyUp and use uploadsInProgress; it will be hidden from customer code 

    window.MyUp = MyUp; 
})(); 

Я не совсем уверен, если это будет решать вопросы закачивать, но это, безусловно, позволит вам сохранить ваше здравомыслие при инстанцировании нескольких объектов.

+0

Большое вам спасибо. Я собираюсь проверить это прямо сейчас. –

+0

Итак, я уже объявляю функции как MyUp.functionname = function() {}. –

+0

... извините, продолжение. И я переместил все прототипы вне скобок конструктора. Нет, я получаю undefined, не является функцией. Что еще мне нужно делать? –

 Смежные вопросы

  • Нет связанных вопросов^_^