Jump to content

Datetime field required


matjazp
 Share

Recommended Posts

I would like to set html required attribute on Datetime field. We have this option on text fields, but not on Datetime (or Integer or...). Is this possible? Like hooking to InputfieldDatetime::getConfigInputfields and adding checkbox? But then, where do I hook to add this required attribute? 

Link to comment
Share on other sites

4 hours ago, matjazp said:

Like hooking to InputfieldDatetime::getConfigInputfields and adding checkbox? But then, where do I hook to add this required attribute?

Yes, you can use the code from InputfieldText::getConfigInputfields almost verbatim in a site/ready.php hook, but since that configuration property isn't initialized in InputfieldDatetime and not set in the field's attributes, you have to add that logic too in another hook. A possible place to do that is in Field::getInputfield:

<?php namespace ProcessWire;

// Add the configuration field:
$wire->addHookAfter("InputfieldDatetime::getConfigInputfields", function(HookEvent $event) {
	$inputfields = $event->return;
	
	$required = $inputfields->getChildByName('required');
	
	if($required) {
		$required->set('columnWidth', 50);
		/** @var InputfieldCheckbox $field */
		$field = wire('modules')->get('InputfieldCheckbox');
		$field->attr('name', 'requiredAttr');
		$field->label = $event->object->_('Also use HTML5 “required” attribute?');
		$field->showIf = "required=1, showIf='', requiredIf=''";
		$field->description = $event->object->_('Use only on fields *always* visible to the user.');
		$field->icon = 'html5';
		$field->columnWidth = 50;
		if($event->object->requiredAttr) $field->attr('checked', 'checked');
		$required->getParent()->insertAfter($field, $required);
	}
});

// This populates the requiredAttr property and sets the HTML attribute
// on the InputfieldDatetime instance:
$wire->addHookAfter("Field::getInputfield", function(HookEvent $event) {
	$input = $event->return;
	if(! $input instanceof InputfieldDatetime) return;
	
	$field = $event->object;
	
	// Configuration value retrieved from the field's settings in the database:
	$requiredAttr = $field->requiredAttr;
	
	// Probably not necessary but there for consistiency:
	if($requiredAttr) $input->requiredAttr = $requiredAttr;
	
	// This sets the HTML attribute
	if($input->required && $requiredAttr && !$input->getSetting('showIf') && !$input->getSetting('requiredIf')) {
		$input->setAttribute('required', 'required');
	}
});

 

  • Like 3
Link to comment
Share on other sites

Thank you @BitPoet In the meantime I found the place to hook - InputfieldDatetime::render. And since I need this for only 2 specific dates, I'm applying the required attribute to the InputfieldDatetime based on the field name (hasField). This way I don't have to save attributes to the field - who knows someday this HTML required attribute might even get it's way to the core (and I'm surprised that it's not there already).

Link to comment
Share on other sites

The HTML required attribute seems like it would be a handy thing to use on all inputfields that play nicely with it, whenever that inputfield is required. Might as well give the user a notice before the form is submitted rather than after.

The hook below does this, but as per the core option for InputfieldText it does not cover "required if" conditions:

$wire->addHookBefore('Inputfield::render', function(HookEvent $event) {
    $inputfield = $event->object;
    $type = substr($inputfield->className, 10);
    // Only for inputfield types that play nicely with the HTML required attribute
    if(!in_array($type, ['Text', 'Email', 'Datetime', 'Textarea', 'Integer', 'Checkbox'])) return;
    // Only if the field is required and has no requiredIf condition
    if($inputfield->required && !$inputfield->requiredIf) $inputfield->attr('required', true);
});

 

  • Like 1
Link to comment
Share on other sites

@Robin S, thank you for your contribution. Your version is handy if you want to target more inputfield types, not just date. Maybe we should not target specific className but rather the class that it extends? In your example, Integer is covered, but Float and Decimal are not. Also, Url is not covered, but since InputfieldUrl extends InputfieldText, required attribute is already available in core. Maybe we should check on what types are specifically not supported, rather than supported?

Link to comment
Share on other sites

16 hours ago, matjazp said:

Maybe we should not target specific className but rather the class that it extends?

You could approach it that way, but I think I would be inclined to keep adding inputfield types to the array that are known to be compatible rather than risk affecting an inputfield that is not compatible. Because the consequences of excluding a inputfield that does work are minimal (user sees a notice after the form is submitted rather than before) but the consequences of including an inputfield that doesn't work are more severe (user cannot submit the form and does not see any notice explaining why).

The HTML required attribute will not work for any inputfield that hides the actual input that holds the value, e.g. CKEditor, AsmSelect, File, Image, PageListSelect, etc. If you take the "extends" option then you need to start excluding inputfields as well as including them - e.g. you might include Textarea and Select because those inputfields will work with HTML required, but you would have to exclude some inputfields that extend those types such as CKEditor or AsmSelect.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...