meeting-room-booking-system / mrbs-code

MRBS application code
Other
128 stars 64 forks source link

Conditional Logic for Custom Fields #3779

Closed dyerry79 closed 2 days ago

dyerry79 commented 1 week ago

Hi, I added three custom fields (req_chair, req_table, req_internet), following my previous javascript pattern, I managed to hide and display the added custom fields. Here's what I did:

  1. In the edit_entry.php, I added a function patterned with the repeat function to generate two radio buttons (yes/no)

image

Upon loading the input boxes and the checkbox are hidden.

The issue is the gap between the textarea and the radio button

  1. The hide/display functions of the radio is working well.

    • If the user clicks yes, it will display the input boxes and the checkbox as shown in the screenshot:

    image

    Would it be possible that the two input boxes and the checkbox below the radio buttons or beside the radio buttons?

Here's what I got so far: Radio buttons

function get_field_logistics_toggle() : FieldDiv
{
    // Create the main field container
    $field = new FieldDiv();
    $field->setAttributes(array(
        'id' => 'rep_type',
        'class' => 'multiline' // Add your desired classes
    ))
    ->setLabel('Requirements');

    // Define radio options for "Need Logistics?" (Yes/No)
    $options = array(
        'no' => 'No',
        'yes' => 'Yes'
    );

    // Create the radio group
    $radio_group = new ElementDiv();
    $radio_group->setAttribute('class', 'group long')
                ->addRadioOptions($options, 'logistics', 'no', true); // Default to "No"
    $field->addControlElement($radio_group);

    return $field;
}
  1. in the get_field_custom function, I called the get_field_logistics_toggle function here
  if ($key == 'terms_and_conditions')
  {
        $fieldset = new ElementFieldset();
        $fieldset->setAttribute('id', 'custom_fields');

        // Add the logistics toggle
        $fieldset->addElement(get_field_logistics_toggle());

    if (is_book_admin())
    {
      $field = new ElementInputHidden(VAR_PREFIX . $key, '1');  // Auto-checked for admins
    }
    else
    {
      $div = new ElementDiv();
      $a = new ElementA();
      $a->setAttribute('href', '#');
      $a->setAttribute('onclick', 'openModal(); return false;');
      $a->setText("Terms and Conditions");

      $span = new ElementSpan();
      $span->setText("I agree to the ", true);
      $span->addElement($a);

      $control = $field->getControl();
      $field->removeControl();

      $div->addElement($control)->addElement($span);
      $field->addElement($div);
    }

        $fieldset->addElement($field);
        return $fieldset;
  }  
  /*------------end terms and conditions ------------*/
  return $field;
  1. and the javascript
document.addEventListener('DOMContentLoaded', function() {
    // References to the radio buttons
    const logisticsRadios = document.getElementsByName('logistics');
    // References to the input fields and their labels
    const chairInput = document.getElementById('f_req_chair');
    const tableInput = document.getElementById('f_req_table');
    const internetCheckbox = document.getElementById('f_req_internet');
    const chairLabel = document.querySelector('label[for="f_req_chair"]');
    const tableLabel = document.querySelector('label[for="f_req_table"]');
    const internetLabel = document.querySelector('label[for="f_req_internet"]');

    // Function to toggle visibility
    function toggleLogisticsFields(show) {
        const displayValue = show ? '' : 'none'; // '' restores the default display style
        chairInput.style.display = displayValue;
        tableInput.style.display = displayValue;
        internetCheckbox.style.display = displayValue;
        chairLabel.style.display = displayValue;
        tableLabel.style.display = displayValue;
        internetLabel.style.display = displayValue;
    }

    // Add event listeners to the radio buttons
    logisticsRadios.forEach(radio => {
        radio.addEventListener('change', function() {
            if (this.value === 'yes') {
                toggleLogisticsFields(true); // Show the fields
            } else {
                toggleLogisticsFields(false); // Hide the fields
            }
        });
    });

    // Initialize the state to "No" (hidden by default)
    toggleLogisticsFields(false);
});

TIA for your usual help.

campbell-m commented 1 week ago

You could simplify the code in get_field_logistics_toggle() by using the class FieldInputRadioGroup. I think this would also arrange your options horizontally rather than vertically.

You could also simplify your JavaScript by using jQuery. I know some people don't like using jQuery, but as the library is loaded anyway you might as well use it.

The issue is the gap between the textarea and the radio button

I don't know what's causing this. You'll need to see what's happening by looking at the CSS and layout using your browser's developer tools.

Would it be possible that the two input boxes and the checkbox below the radio buttons or beside the radio buttons?

You can change the field order by using the config setting $edit_entry_field_order.

dyerry79 commented 1 week ago

Hi Campbell, I managed to have it his way for admin

image

However, the display is different for non-admin users

.image As you can see, there's a huge gap between the logistics and radio buttons.

I'm pretty sure it's the placement of the terms and conditions checkbox has something to with it. Here's how I did it

  if ($key == 'terms_and_conditions')
  {

    $fieldset = new ElementFieldset();
    $fieldset->setAttribute('id', 'rep_info');
    // Add the logistics toggle
    $fieldset->addElement(get_field_logistics_toggle());

    if (is_book_admin())
    {
      $field = new ElementInputHidden(VAR_PREFIX . $key, '1');  // Auto-checked for admins
    }
    else
    {
      $div = new ElementDiv();
      $a = new ElementA();
      $a->setAttribute('href', '#');
      $a->setAttribute('onclick', 'openModal(); return false;');
      $a->setText("Terms and Conditions");

      $span = new ElementSpan();
      $span->setText("I agree to the ", true);
      $span->addElement($a);

      $control = $field->getControl();
      $field->removeControl();

      $div->addElement($control)->addElement($span);
      $field->addElement($div);
    }

      $fieldset->addElement($field);
      return $fieldset;
  }  
  /*------------end terms and conditions ------------*/
  return $field;

Any idea?

campbell-m commented 1 week ago

I don't know how you've generated the three extra fields (Chair Qty etc.), but you'd be better off just letting them each be their own field, rather than part of another one. That way they'll appear in a vertical column and you won't have that big gap. It'll also work better on a narrow screen such as a smart phone.

dyerry79 commented 1 week ago

Thanks Campbell.

I've been trying to play around without overriding the original method MRBS was designed to deal with custom fields, but to no avail, I haven't made it work. I've managed to display the requirements (chairs, tables and internet) vertically by doing some revisions in the get_field_custom. I'll post the code and the screenshot for your reference.

code: ` $field = get_field_entry_input($params);

if ($key == 'req_type') {
    $fieldset = new ElementFieldset();
    $fieldset->setAttribute('id', 'requirements');

    // Add the logistics toggle using the provided function
    $fieldset->addElement(get_field_logistics_toggle());

    // Input for Number of Chairs
    $chairsDiv = new ElementDiv();
    $chairsDiv->setAttribute('id', 'chairsDiv'); // Set ID for JavaScript
    $chairsLabel = new ElementLabel();
    $chairsLabel->setText('Chairs'); // Updated label
    $chairsInput = new FieldInputNumber('num_chairs', '1'); // Default value is 1
    $chairsInput->setAttribute('min', '1'); // Minimum value is 1
    $chairsDiv->addElement($chairsLabel);
    $chairsDiv->addElement($chairsInput);
    $chairsDiv->setAttribute('style', 'display: none;'); // Initially hidden
    $fieldset->addElement($chairsDiv);

    // Input for Number of Tables
    $tablesDiv = new ElementDiv();
    $tablesDiv->setAttribute('id', 'tablesDiv'); // Set ID for JavaScript
    $tablesLabel = new ElementLabel();
    $tablesLabel->setText('Tables'); // Updated label
    $tablesInput = new FieldInputNumber('num_tables', '1'); // Default value is 1
    $tablesInput->setAttribute('min', '1'); // Minimum value is 1
    $tablesDiv->addElement($tablesLabel);
    $tablesDiv->addElement($tablesInput);
    $tablesDiv->setAttribute('style', 'display: none;'); // Initially hidden
    $fieldset->addElement($tablesDiv);

    // Checkbox for Internet Requirement
    $internetDiv = new ElementDiv();
    $internetDiv->setAttribute('id', 'internetDiv'); // Set ID for JavaScript
    $internetLabel = new ElementLabel();
    $internetLabel->setText('Internet'); // Updated label
    $internetCheckbox = new FieldInputCheckbox('internet', '1'); // Checkbox name and value
    $internetDiv->addElement($internetLabel); // Add the label before the checkbox
    $internetDiv->addElement($internetCheckbox); // Add the checkbox after the label
    $internetDiv->setAttribute('style', 'display: none;'); // Initially hidden
    $fieldset->addElement($internetDiv);

    return $fieldset;
}

if ($key == 'actual_start' or $key == 'actual_end' or $key == 'actual_status'){
    $field = new ElementInputHidden();
}

if ($key == 'contact_requirements') {
    $div = new ElementDiv();

    // Add the main control element (e.g., the textarea)
    $control = $field->getControl();
    $field->removeControl();
    $div->addElement($control);

    // Check if the user is NOT an admin
    if (!is_book_admin()) {
        $a = new ElementA();
        $a->setAttribute('href', '#');
        $a->setAttribute('onclick', 'openNModal(); return false;');
        $a->setText("Notation");

        $span = new ElementSpan();
        $span->addElement($a);

        // Add the span containing the "Notation" link after the textarea
        $div->addElement($span);
    }

    $field->addElement($div);
}
return $field;

}

$full_class = NAMESPACE . "\Form\$class"; $field = new $full_class();

$field->setLabel(get_loc_field_name(_tbl('entry'), $key)) ->setControlAttributes(array('name' => VAR_PREFIX . $key, 'disabled' => $disabled, 'required' => !empty($is_mandatory_field["entry.$key"])));

if ($custom_field['nature'] == 'decimal') { list( , $decimal_places) = explode(',', $custom_field['length']); $step = pow(10, -$decimal_places); $step = number_format($step, $decimal_places); $field->setControlAttribute('step', $step); }

if ($class == 'FieldTextarea') { if (isset($custom_fields[$key])) { $field->setControlText($custom_fields[$key]); } if (null !== ($maxlength = maxlength("entry.$key"))) { $field->setControlAttribute('maxlength', $maxlength); } } elseif ($class == 'FieldInputCheckbox') { $field->setControlChecked(!empty($custom_fields[$key])); } else { $field->setControlAttribute('value', (isset($custom_fields[$key])) ? $custom_fields[$key] : null); }

/------------implement terms and conditions ------------/ if ($key == 'req_chair' OR $key == 'req_table' OR $key == 'req_internet'){ $field = new ElementInputHidden(); } if ($key == 'terms_and_conditions') { if (is_book_admin()) { $field = new ElementInputHidden(VAR_PREFIX . $key, '1'); } else { $div = new ElementDiv(); $a = new ElementA(); $a->setAttribute('href', '#'); $a->setAttribute('onclick', 'openModal(); return false;'); $a->setText("Terms and Conditions");

  $span = new ElementSpan();
  $span->setText("I agree to the ", true);
  $span->addElement($a);

  $control = $field->getControl();
  $field->removeControl();

  $div->addElement($control)->addElement($span);
  $field->addElement($div);
}

}
/------------end terms and conditions ------------/ return $field;`

screenshot image

Issue: The location of the terms and conditions

You help is very much appreciated. TIA

campbell-m commented 1 week ago

I don't know. You need to look at the HTML structure in your developer tools. It looks like the terms and conditions field is a level too low.

I still think there's no need for you to have any code for the chairs etc. MRBS should just do it all automatically.

dyerry79 commented 1 week ago

I still think there's no need for you to have any code for the chairs etc. MRBS should just do it all automatically.

Thanks for your patience Campbell. I got what I want now. I created the radio buttons within the get_field_custom function instead of creating them through a function (get_field_logistics_toggle()).

image