Lambat "Tambahkan item lain" dengan bidang bernilai tak terbatas

8

Di Drupal 7, ketika Anda memiliki simpul dengan bidang yang memiliki nilai tidak terbatas (katakanlah, bidang gambar), waktu respons "tambahkan item lain" menjadi sangat lambat setelah Anda menambahkan 10 - 20 item. Bagaimana Anda mengatasi masalah ini? Pernahkah Anda mengalami masalah ini?

Saya membuat proyek, di mana pengguna dapat menambahkan hingga 100 nilai bidang gambar yang secara teori memiliki pengaturan nilai tidak terbatas. Tapi, setelah Anda menambahkan selusin gambar, setiap klik baru pada "Tambahkan item lain" menjadi lebih lambat dari sebelumnya. Saya tahu ini terjadi karena fakta, bahwa Drupal membangun kembali bidang ini dan semua nilainya setelah setiap permintaan ajax, sehingga semakin banyak nilai yang Anda tambahkan semakin banyak pekerjaan yang harus dilakukan Drupal pada setiap permintaan "ajax", tetapi, sebenarnya, ini bukan hal yang cukup hebat.

Apakah ada pendekatan tentang cara mengubah / mengesampingkan perilaku seperti itu?

Timur Kamanin
sumber

Jawaban:

3

membangun pada jawaban oleh Charlie, saya menemukan bahwa dibutuhkan jumlah waktu yang sama untuk memuat ulang blok jika Anda menambahkan 1 atau 100 item, jadi di sini adalah trik untuk menambahkan daftar pilih angka dalam bentuk di sebelah 'tambah lebih banyak sehingga Anda dapat memilih berapa banyak yang Anda tambahkan. Ini menghemat banyak waktu dan masih fleksibel. Bisa dibungkus dengan modul kecil

<?php
/**
* Implements hook_field_attach_form()
*/
function village_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode){
  $options = array('language' => field_valid_language($langcode));
  // Merge default options.
  $default_options = array(
    'default' => FALSE,
    'deleted' => FALSE,
    'language' => NULL,
  );
  $options += $default_options;
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
  $instances = _field_invoke_get_instances($entity_type, $bundle, $options);
  // Iterate through the instances.
  $return = array();
  foreach ($instances as $instance) {
    // field_info_field() is not available for deleted fields, so use
    // field_info_field_by_id().
    $field = field_info_field_by_id($instance['field_id']);
    $field_name = $field['field_name'];
    //If we are looking at our field type and specific widget type, and we are multiple entries
    if($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED){
      //Check just in case the button is here, and add another #submit function
      if(isset($form[$field['field_name']]['und']['add_more'])){
        // add a simple select list, this defaults to numb 3
        $form[$field['field_name']]['add_more_number'] = array(
          '#type' => 'select',
          '#title' => t('Add more no.'),
          '#options' => drupal_map_assoc(range(0, 50)),
          '#default_value' => 2,
        );
        $form[$field['field_name']]['und']['add_more']['#submit'][] = 'village_field_add_more_submit';
        $form[$field['field_name']]['und']['add_more']['#value'] = 'Add more rows';
      }
    }
  }
}
function village_field_add_more_submit($form, &$form_state){
  $button = $form_state['triggering_element'];
  // Go one level up in the form, to the widgets container.
  $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1));
  $field_name = $element['#field_name'];
  $langcode = $element['#language'];
  $parents = $element['#field_parents'];
  // Alter the number of widgets to show. items_count = 0 means 1.
  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
  //get the number from the select
  $numbtoadd = $form[$field_name]['add_more_number']['#value'];
  if($numbtoadd){
    $field_state['items_count'] += $numbtoadd;
    field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
    $form_state['rebuild'] = TRUE;
  }
}
?>

Saya juga memposting saran di Drupal.org di https://drupal.org/node/1394184#comment-8252701 di mana op memiliki masalah yang sama.

jowan sebastian
sumber
Saya mengadaptasi kode di atas untuk bidang khusus dengan kardinalitas tanpa batas dan itu bekerja dengan baik untuk saya. Satu-satunya perubahan yang saya buat pada logika inti adalah mengurangi 1 dari $ numbtoadd sebelum menggunakannya. Saya pikir ini karena items_count kurang terwakili karena berbasiskan nol?
Dave Bruns
2

Ini blowback dari sifat API bentuk dan bagaimana hal itu membuat seluruh $formdan $form_statetersedia kembali di server. Ini adalah hal yang keren karena banyak alasan, meskipun saya setuju bahwa itu bisa sangat mengganggu dari perspektif kinerja. Beberapa statistik pada server Ubuntu 12.04 yang menjalankan Apache2 dengan PHP-FPM:

  • Saya menambahkan 30 item ke bidang file, menambahkan dan mengunggah 1 sekaligus, dan total waktu untuk unggahan + respons server + penyisipan javascript elemen baru berjalan dari 414 milidetik, meningkat setiap unggahan berurutan mulai dari 0-20 milidetik, berakhir pada 800 milidetik untuk perjalanan nomor 30.

  • Saya mengklik "Tambahkan item lain" untuk bidang teks tak terbatas 100 kali, dan total waktu dari 337 milidetik hingga 1,3 detik. Jika formulir saya lebih kompleks, jumlah ini hanya akan meningkat.

Di $form_state['fields']['your_field_name']['und']ada properti yang disebut items_count. Ini digunakan untuk menghitung jumlah widget bidang yang harus ditampilkan untuk bidang tertentu. Saya akan merekomendasikan Anda gunakan hook_field_attach_form()untuk mengubah $form_state sebelum widget bidang dibangun dan mengatur items_countproperti bidang menjadi jumlah yang lebih besar, sehingga memberi Anda jumlah bidang yang Anda butuhkan segera. Pengguna masih dapat menambahkan lebih banyak item. Terserah kepada Anda untuk menemukan cara yang lebih baik untuk menyembunyikan item tambahan dari membuat formulir 10 halaman; mungkin div dengan overflow: scroll;bisa bekerja. Bagaimanapun, ini mungkin menjadi titik awal bagi Anda untuk menemukan sesuatu yang memungkinkan alur kerja Anda berjalan lebih cepat:

function mymodule_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
  $form_state['field']['field_my_field'][$langcode]['items_count'] = 100;
}

Sunting: Kode sampel tidak memiliki logika untuk memastikan kode hanya berjalan untuk formulir yang sesuai dan tidak akan memungkinkan Anda untuk 'menambahkan item lain'. Saya akan merevisi ini ketika saya memiliki contoh kerja yang lebih baik secara lokal.

Charlie Schliesser
sumber
Halo Charlie, saya berpikir tentang trik yang Anda uraikan juga, tetapi keadaan menjadi lebih buruk, ketika pengguna ingin menyusun ulang bidang (dalam kasus saya, ini merupakan persyaratan penting). Saat Anda mencoba menyusun ulang satu dari 100 bidang melalui drag'n'drop, peramban hang selamanya ...
Timur Kamanin
Apakah hanya bergantung pada pemesanan ulang bidang file atau bidang teks juga? Tampaknya aneh, karena draggable.js seharusnya tidak mengirim apa pun kembali ke server, tetapi hanya mendengarkan perubahan baris dan kemudian memperbarui bidang input tersembunyi. Juga, browser dan versi apa yang Anda alami dengan hang-in? Saya pikir apa pun yang kami temukan di sini dapat bermanfaat bagi banyak pengguna lain.
Charlie Schliesser
Ya, jika Anda memiliki case use yang dapat direproduksi dari draggable.js yang tergantung pada masalah inti.