processwire / processwire-requests

ProcessWire feature requests.
39 stars 0 forks source link

InputfieldRadios more flexibility for custom option attributes #432

Open jlahijani opened 2 years ago

jlahijani commented 2 years ago

I use ProcessWire's form API to build forms as opposed to using regular HTML.

One annoying limitation is the inability to assign custom attributes directly to radio options. This is a common use case with tools like Alpine.js where I would want to throw a x-model="something" directly onto an <option>. Right now, if I do this:

$field->addOption("billing", "Ship to the above address", ['x-model'=>'deliver']);

... the x-model attribute will get added to the LABEL field of that option, NOT the option itself.

Is it possible to improve InputfieldRadios so we can add custom attributes directly to the option itself? Please. :)

jlahijani commented 2 years ago

Related from 2016: https://github.com/ryancramerdesign/ProcessWire/issues/1820

Is it possible we can assign directly to the <option>? Alpine.js and Vue work in a specific way, so it would just make it so much more convenient.

jlahijani commented 1 year ago

@ryancramerdesign Would this be something you can look into now that the master version has been released? It would really help make working with Hyperscript or Alpine.js much easier.

jlahijani commented 1 year ago

I solved this for now using using this hook:

// move hyperscript and alpine.js attributes from <label> to <input> for better compatibility
$wire->addHookAfter('InputfieldRadios::render', function(HookEvent $event) {
  $html = $event->return;
  $dom = new \DOMDocument;
  libxml_use_internal_errors(true);
  $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
  libxml_clear_errors();
  $xpath = new \DOMXPath($dom);
  foreach ($xpath->query("//label") as $label) {
    $input = $xpath->query("./input", $label)->item(0);
    foreach ($label->attributes as $attr) {
      $name = $attr->name;
      // hyperscript attributes: _, hs, data-hs
      // alpine.js attributes: x-, @
      if ($name === '_' || $name === 'hs' || $name === 'data-hs' || strpos($name, 'x-') === 0 || strpos($name, '@') === 0) {
        $input->setAttribute($name, $attr->value);
        $label->removeAttribute($name);
      }
    }
  }
  $event->return = $dom->saveHTML();
});