Pola autouzupełniania oparte na innym polu

10

Mam bardzo złożoną sytuację, w której potrzebuję porady. Mam typ zawartości my_content, do którego jest dołączone pole kolekcji pól field_mycollection, które ma pole odniesienia encji odnoszące się do użytkownika field_my_userreference, pole telefonu, pole field_my_phonetekstowe field_my_texti inne pole tekstowe field_my_anothertext.

My Content
|_ field_mycollection
   |_ field_my_userreference
   |_ field_my_phone
   |_ field_my_text
   |_ field_my_anothertext

Jednostka użytkownika ma również pola field_my_phone, field_my_texta field_my_yetanothertextta ostatnia ma inną nazwę komputera.

Co chcę zrobić, jeśli w my_contentformularzu edycji / dodania field_my_userreferenceużytkownik jest zaznaczony, pozostałe pola powinny zostać automatycznie wypełnione danymi wybranego użytkownika. Pola automatycznie wypełnione powinny nadal być edytowalne.

Jak mogę osiągnąć ten cel? Chciałbym to zrobić, jeśli to możliwe, z pewnym kodowaniem, używając hook_form_FORM_ID_alter().

Елин Й.
źródło
Czy potrzebujesz, aby stało się to na żywo w formie, czy w trybie oszczędzania?
Mołot
Na żywo w formie. Zaimplementowałem już to, że przy zapisie dane zostaną pobrane z encji użytkownika, jeśli pozostaną puste. Ale właściwie to, czego potrzebuję w formularzu :(
Елин Й.
OK, podałem moją odpowiedź.
Mołot

Odpowiedzi:

11

Jeśli chcesz, aby stało się to na żywo, a wszystkie pola są już w formularzu, najbezpieczniejszym sposobem byłoby hook_form_FORM_ID_alter()dodanie następujących elementów do formularza:

$form['#attached']['js'] = array(
  drupal_get_path('module', 'module_name') . '/js/copy_field_value.js',
);

Następnie w copy_field_value.jstworzeniu zachowania:

(function($) {
  Drupal.behaviors.moduleNameCopyFieldValue = {
    attach: function (context, settings) {

      // Repeat this for all fields as needed
      $('#source', context).on('blur', function () { 
        // above you can use change instead of blur if element is not changed by another js
        if (!$('#destination').val() || 0 === $('#destination').val().length) {
          $('#destination').val($(this).val());
          // wrap line above in "if no value" like I did, or other condition you like
        }
      });
      // end of "repeat this"
    }
  };
})(jQuery);

Można również użyć hook_form_FORM_ID_alter()do dodania #ajaxparametru do pola źródłowego, ale spowoduje to, że formularz będzie wywoływał serwer na każdej kopii pola. Jeśli potrzebujesz zapytać bazę danych, jest to dobry sposób. Byłoby dość szerokie, aby opisać to na nowo tutaj. Musisz zmienić $form_state["input"]tablicę, aby zaktualizować rzeczywiste wartości widoczne dla użytkownika. Zrób to w funkcji tworzenia formularza, owijając go, issetaby uniknąć powiadomień.

Jeśli twoim elementem formularza jest $form["something"]["something"]["element"], jego wartość będzie $form_state["input"]["something"]["something"]["element"]zawarta - i możesz go ustawić w hook_form_alterporządku, pamiętaj tylko, aby wziąć oba $formi $form_stateprzez odniesienie.

Uwaga : .on()metoda została dodana w jQuery 1.7, więc będziesz potrzebować jQuery Update, aby użyć tej odpowiedzi bezpośrednio lub przetłumaczyć mój kod do użycia .change()lub .blur()metody.

Mołot
źródło
Wielkie dzięki za instrukcje! Nie jestem zbyt dobry w JS API Drupala. Czy wyjaśniłbyś, w jaki sposób otrzymuję wartości pól od encji użytkownika? Na przykład, jeśli wybrano użytkownika, jak mogę wypełnić następne pola informacjami tego użytkownika?
Елин Й.
1
@ ЕлинЙ. Sztuką tutaj nie jest dbanie o tło php. Wystarczy zidentyfikować parametry identyfikatora <input>tagów za pomocą Firebug lub podobnego narzędzia dla swojej ulubionej przeglądarki. Lub użyj dowolnego innego selektora jQuery. Stanie się tak tylko w przeglądarce, więc masz to, co masz na ekranie. Z drugiej strony, jeśli chcesz faktycznie zapytać do bazy danych (wydaje mi się, że tego nie zauważyłem), #ajaxjest to droga. Ale byłoby dość szerokie. Musisz zmienić $form_state["values"]tablicę, aby zaktualizować rzeczywiste wartości widoczne dla użytkownika. Zrób to w funkcji tworzenia formularza, owijając go, issetaby uniknąć powiadomień.
Mołot
Jeszcze raz dziękuję @ Mołot, postaram się go wdrożyć jutro, a może dziś wieczorem. Wygląda na to, że potrzebuję kilku godzin, aby naprawdę działało, jeśli nie więcej.
Елин Й.
@ ЕлинЙ. powodzenia, zachęcamy do powrotu z dalszymi pytaniami i linkowania ich tutaj w komentarzach, jeśli są połączone. Zaktualizowałem trochę odpowiedź, btw.
Mołot
1
Ok, eksperymentuję trochę i napiszę swoje doświadczenia.
Елин Й.
4

Możesz to zrobić za pomocą obliczonego modułu polowego

Pole obliczeniowe to bardzo wydajny moduł pola CCK, który pozwala dodawać niestandardowe „pola obliczane” do typów zawartości. Te pola obliczeniowe są wypełniane wartościami zdefiniowanymi za pomocą kodu PHP. Możesz czerpać z wszystkiego, co jest dostępne dla Drupala, w tym z innych pól, bieżącego użytkownika, tabel bazy danych, nazywasz to. (Czujesz moc jeszcze? :)) Możesz także wybrać, czy chcesz przechowywać obliczone wartości pól w bazie danych z innymi polami zawartości, czy też „obliczać” je w locie podczas widoków węzłów. (Chociaż należy zauważyć, że użycie Widoku wymaga wartości przechowywanych w bazie danych). To pole jest dosłownie szwajcarskim scyzorykiem pól CCK. Zacznij więc gotować wartości oparte na PHP!

4life
źródło
Dziękuję za szybką odpowiedź. Brzmi bardzo obiecująco. Chociaż nie chcę instalować modułu do tego, ale po prostu napisz trochę kodu, ponieważ potrzebuję takiej funkcjonalności tylko w tym formularzu, a rzeczywisty system jest już zbyt duży i wiele modułów jest zainstalowanych dla różnych funkcji.
Елин Й.
Po drugie, czy możliwe jest użycie tego modułu dla użytkownika, który tworzy lub edytuje węzeł, aby ręcznie zastąpić pola automatycznie wypełniane i zapisać? Tak więc w encji użytkownika i my_content są zapisywane różne wartości.
Елин Й.
Zależy to od sposobu konfiguracji
życie
Dzięki @ 4life, spróbuję również, jeśli nie będę w stanie tego osiągnąć dzięki kodowaniu, korzystając z instrukcji Mołota.
Елин Й.
2

Chcę napisać, jak to osiągnąłem dzięki wielkiej pomocy @ Mołot.

  1. Zaimplementowano hook_form_FORM_ID_alter () .
  2. Dodano zawijanie div wokół kolekcji pola.
  3. Ponieważ kolekcja my field jest polem o wielu wartościach, iteruje się nad nią i ustawia #ajaxwłaściwość pola field_my_userreference.
  4. Utworzono funkcję zwrotną, która po prostu zwraca element kolekcji pola z powrotem.
  5. Sprawdzane w implementacji hook_form_FORM_ID_alter (), jeśli ustawiono $ form_state dla kolekcji pól. Jeśli tak, pobierz wartości z encji użytkownika i wypełnij pola wejściowe formularza tymi wartościami.

Mój kod wygląda następująco:

function MYMODULE_form_my_content_node_form_alter(&$form, &$form_state, $form_id) {
  $form['field_mycollection']['#prefix'] = '<div id="mycollection-wrapper">';
  $form['field_mycollection']['#suffix'] = '</div>';
  foreach ($form['field_mycollection']['und'] as $key => $fc_mycollection) {
    if (is_numeric($key)) {
      $form['field_mycollection']['und'][$key]['field_my_userreference']['und']['#ajax'] = array(
        'callback' => 'MYMODULE_mycollection_callback',
        'wrapper' => 'mycollection-wrapper',
      );
      if (isset($form_state['values']['field_mycollection']['und'][$key]['field_my_userreference']['und'][0]['target_id'])) {
        $user_wrapper = entity_metadata_wrapper('user', $form_state['values']['field_mycollection']['und'][$key]['field_my_userreference']['und'][0]['target_id']);
        $form_state['input']['field_mycollection']['und'][$key]['field_my_text']['und'][0]['value'] = $user_wrapper->field_my_text->value() ? $user_wrapper->field_my_text->value() : '';
        $form_state['input']['field_mycollection']['und'][$key]['field_my_anothertext']['und'][0]['value'] = $user_wrapper->field_my_text->value() ? $user_wrapper->field_my_yetanothertext->value() : '';
      }
    }
  }
}

function MYMODULE_mycollection_callback($form, &$form_state) {
  return $form['field_mycollection'];
}
Елин Й.
źródło