Jump to content
Marco Ro

Change label position in Inputfield

Recommended Posts

Hi,

I need to change the position of the label tag. In all render the input field look like this:

<div class="Inputfield" id="">
  <label class="InputfieldHeader" for="...">Email</label>
  <div class="InputfieldContent">
    <input id="..." name="..." class="..." type="" maxlength="512" autocomplete="off">
  </div>
</div>

I would like move the label tag inside the InputfieldContent after the input tag.

I try to work around the render hook, but didn't found a solution, and also I'm not sure is this the way. 

How can I do it?

Thank you.

Share this post


Link to post
Share on other sites

Hi Marco Ro,

51 minutes ago, Marco Ro said:

I need to change the position of the label tag. In all render the input field look like thisI would like move the label tag inside the InputfieldContent after the input tag.

Just move it where you want to have it:

<div class="Inputfield" id="">
  <div class="InputfieldContent">
    <input id="42" name="..." class="..." type="" maxlength="512" autocomplete="off">
	<label class="InputfieldHeader" for="42">Email</label>
  </div>
</div>	

Through the for attribute you assign the label to the wanted input element, refering to its id (here 42).

That said, you should consider to avoid additional div elements and just use the semantic elements:

    <input id="42" name="..." class="Inputfield" type="" maxlength="512" autocomplete="off">
	<label for="42">Email</label>

This might be sufficient - of course that depends on your special use case...

 

Share this post


Link to post
Share on other sites

Thank you @ottogal, yes this could be a solution, but I have make one like of code for every input. I will like have this render for all the input. For this reason I was thinking of a hook solution on Inputfield. 

 

Share this post


Link to post
Share on other sites

@Marco Ro Why do you want to change that? And what's the situation? Do you use PW's inputfield form to create forms in the frontend? Do you want to re-style the labels and/or input fields? Maybe there's a CSS solution? Or is this even something from FormBuilder?

Share this post


Link to post
Share on other sites

Hi @dragan thank you, yes I need this for make a re-style of css, I use the field in the module LoginRegister and Padloper, all of these render directly the Inputfield.

I can't find a solution only with the css, I need to move the tag label because it has to work inside the InputfieldContent. I need move the text label inside the input, when write inside the input the label text will be smaller and move across the InputfieldContent box. 

I try to use the appendTo(), but without using a unique ID or class it doesn't work well. I also try to use the placeholder attribute, but doesn't work like we would like.

I never use the FormBuilder module, I read that is very nice module and sure I can make every contact form that I need, included the login form, but in this way I have also to write all the system for the login form like the registration, the forget password etc.. Also I probably I can't use FormBuilder with Padloper module. 

There are no way to move the label inside the InputfieldContent? 


 

 

 

Share this post


Link to post
Share on other sites

@Marco Ro If you would draw a little sketch, and show exactly what you want to do, and how it's supposed to look like visually (it's still not clear to me from your description), maybe there is a way with CSS only. And perhaps also show what it looks out now, out of the box, for comparison.

e.g. if all you want is to place the label on the left, and the input on the right, you could do it easily with flexbox: https://codepen.io/dragan1700/pen/JjdRYVE

Share this post


Link to post
Share on other sites

@Marco Ro, you can use InputfieldWrapper::setMarkup() to customise the markup of inputfields.

See the defaultMarkup property as a starting point for what can be customised:

/**
 * Markup used during the render() method - customize with InputfieldWrapper::setMarkup($array)
 *
 */
static protected $defaultMarkup = array(
	'list' => "<ul {attrs}>{out}</ul>",
	'item' => "<li {attrs}>{out}</li>", 
	'item_label' => "<label class='InputfieldHeader ui-widget-header{class}' for='{for}'>{out}</label>",
	'item_label_hidden' => "<label class='InputfieldHeader InputfieldHeaderHidden ui-widget-header{class}'><span>{out}</span></label>",
	'item_content' => "<div class='InputfieldContent ui-widget-content{class}'>{out}</div>", 
	'item_error' => "<p class='InputfieldError ui-state-error'><i class='fa fa-fw fa-flash'></i><span>{out}</span></p>",
	'item_description' => "<p class='description'>{out}</p>", 
	'item_head' => "<h2>{out}</h2>", 
	'item_notes' => "<p class='notes'>{out}</p>",
	'item_detail' => "<p class='detail'>{out}</p>", 
	'item_icon' => "<i class='fa fa-fw fa-{name}'></i> ",
	'item_toggle' => "<i class='toggle-icon fa fa-fw fa-angle-down' data-to='fa-angle-down fa-angle-right'></i>", 
	// ALSO: 
	// InputfieldAnything => array( any of the properties above to override on a per-Inputifeld basis)
	);

There are still some limitations (e.g. item_label is always rendered before item_content) but you can get closer to what you want like so:

InputfieldWrapper::setMarkup([
	'list' => "<div {attrs}>{out}</div>",
	'item' => "<div {attrs}><div class='InputfieldContent'>{out}</div></div>",
	'item_label' => "<label class='{class}' for='{for}'>{out}</label>",
	'item_content' => "{out}",
	'item_toggle' => "",
]);

$form = $modules->InputfieldForm;

$f = $modules->InputfieldText;
$f->name = 'greeting';
$f->label = 'Greeting';
$form->add($f);

$f = $modules->InputfieldSubmit;
$form->add($f);

echo $form->render();

2020-02-20_082322.png.d90ea96f0f7fedb903c143a7a257e45f.png

 

11 hours ago, Marco Ro said:

I need move the text label inside the input, when write inside the input the label text will be smaller and move across the InputfieldContent box. 

If I understand right you don't really need to change the markup to do this. The label element can never literally be inside the input element, but you can position it overlaying the input using CSS with the default markup.

.Inputfield { position:relative; }
.InputfieldHeader { position:absolute; left:5px; top:3px; font-size:12px; text-transform:uppercase; }
input[type=text] { padding:17px 5px 5px; border:1px solid #ccc; }
.InputfieldSubmit { margin-top:20px; }

2020-02-20_083451.png.abc9ad1ecc91a0af49300ddbc295db4d.png

If you want to change the label styling when the input is focused you can use some JS to add a class to the parent .Inputfield element when its child input is focused.

Share this post


Link to post
Share on other sites

Hi @Robin S and @dragan, sorry fro the late reply. 

Ok thank you! It's very nice, I can also use $defaultClasses to add class and not use jquery. 

About the css I find a solution and the result is very beautiful.

1455807302_Schermata2020-02-20alle08_37_15.png.9a467d51d32392442bc3402e7673ddcf.png

Thank you so much.

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Juergen
      Hello @ all,
      I am creating a new inputfield/fieldtype to store opening hours, but I am struggeling to save values from multiple dynamic created inputfields in 1 column of the database.
      Scenario:
      The user can enter one or more opening times per day in a UI.
      Fe:
      Monday open from 08:00 to 12:00 and from 14:00 to 17:00 Tuesday open from 08:00 to 12:00 and from 14:00 to 19:00 and so on
      Via a little JavaScript you can add as much opening times as you need per day - the additional inputfield will be created dynamically.
      After form submission all the values are in the POST array -> this works (see example below):
      ProcessWire\WireInputData Object ( [openinghours_mo-0-start] => 09:00 [openinghours_mo-0-finish] => 13:00 [openinghours_mo-1-start] => 14:00 [openinghours_mo-1-finish] => 18:00 [openinghours_mo-2-start] => 21:00 [openinghours_mo-2-finish] => 23:00 [openinghours_tu-0-start] => 09:00 [openinghours_tu-0-finish] => 13:00 [openinghours_tu-1-start] => 14:00 [openinghours_tu-1-finish] => 18:00 [openinghours_we-0-start] => 09:00 [openinghours_we-0-finish] => 13:00 [openinghours_we-1-start] => 14:00 [openinghours_we-1-finish] => 18:00 [openinghours_th-0-start] => 09:00 [openinghours_th-0-finish] => 13:00 [openinghours_th-1-start] => 14:00 [openinghours_th-1-finish] => 18:00 [openinghours_fr-0-start] => 09:00 [openinghours_fr-0-finish] => 13:00 [openinghours_fr-1-start] => 14:00 [openinghours_fr-1-finish] => 18:00 [openinghours_sa-0-start] => [openinghours_sa-0-finish] => [openinghours_so-0-start] => [openinghours_so-0-finish] => ) The property name is always the name attribute of the field 😉 . If the property is empty means closed on that day.
      Now I need to combine all those values into 1 array (or json array) and store it in the database in 1 column called 'hours' in my case (see screenshot below):

      In my ___processInput(WireInputData $input) method I have tried to make it work like this:
      public function ___processInput(WireInputData $input): self { $name = $this->attr('name'); $value = $this->attr('value'); //input object includes always every input on the page, so lets filter out only inputs from this field //we need to do this, because the number of values is variable - so extract only values that starts with $name.'_' $nameAttributes = []; foreach($input as $key=>$value){ if(substr($key, 0, strlen($name.'_')) === $name.'_'){ $nameAttributes[$key] = $value; } } // loop through all inputfields of this fieldtype $time_values = []; foreach($nameAttributes as $nameAttr => $value) { $time_values[$nameAttr] = $value; } } //save it in the database $input->set('hours', serialize($time_values)); return $this; } The only important part of this code is the last part with the serialize function.
      After saving it will create a record in the database, but the value is always NULL (default value) (see below).

      Checking $time_values returns all the values, but printing out "$this" shows me that the property "hours" inside the Openinghours object is empty (see below) - so the mistake must be there, but I dont know where?!?!?!?
      [title] => Home [openinghours] => ProcessWire\OpeningHours Object ( [data] => Array ( [hours] => ) ) If I check the sleepValue() method or the sanitizeValue() - they are also empty. So it seems that the values will not reach these methods. I havent found a clear documentation of whats going on behind the saving process of an inputfield.
      As far as I know the saving process starts with the form submission. The values are in the POST array and will be processed by the processInput() method. Before they will be saved in the database they will be sanitized by the sanitizeValue() mehtod and afterwards they will be prepared for storage in the sleepValue() method.  The last step is the storage itself.
      Has someone an idea what is missing by storing values from multiple fields into 1 database column or has someone a working example of such a scenario on github to help me out.
      A clear explanation of the storage process will be also helpful.
      Thanks and best regards
    • By Juergen
      Hello @ all!
      I want to share a simple fieldtype and inputfield to store address data with you.
      I have created this inputfield for learning purposes and it has no fancy functionality. It is simply for storing address data such as street, number, postalcode and so on in one table. As an addition you can store latitude and longitude too, so you can use them in maps.
      Here is a screenshot of what it looks like:

      You can select which fields are mandatory and you can choose if the inputs for longitude and latitude should be displayed. These settings can be configured in the field configuration.
      If you find this inputfield useful you can download it at https://github.com/juergenweb/FieldtypeSimpleAddress
      There you will find a detailed explanation. If you have an idea of an usefull feature that can be added or you have detected a bug, please report it in my github account.
       
    • By MarkE
      Please note that the updated version of this script and any other associated info is now at https://github.com/MetaTunes/Form-update
      I had a need to interactively update the page choices in a multi-choice page select field. I chose to do this with a general-purpose piece of jQuery. By combining it with a InputfieldPage::getSelectablePages hook, you can get the trigger field to alter the selectable pages interactively.  I have also found this to be useful in a number of other situations - e.g. updating a RuntimeMarkup field for changes on a page. There may be more elegant ways of achieving this (I'm open to suggestions), but in case it is useful to others, I'll post it here. Hopefully the comments in the script are self-explanatory and describe how to use it. Note that there are several console.log statements to help with debugging, which you can remove once happy with its operation.
      Happy to answer any questions (if I can 😉 ). Also, if anyone can explain how to get it working fully with checbox/toggle ad radio buttons, I would be grateful.
      /* Script to refresh a form content when an element gets changed To work across all admin pages, this script needs to be loaded in admin.php – add the line $config->scripts->add($config->urls->templates . "scripts/form-update.js"); before the final require in templates/admin.php. Typical use is to modify other elements based on a select drop-down change The trigger element can have the following data attributes assigned to it (typically set these with $myInputfield->attr() in a module or hook): * data-action="form-update" : Required to run the script. * data-update-target="#myid1" : Required - the element to change. Note that this should not be the whole form, otherwise .find(target) will not find it. * data-confirm="Some confirmation text": Optional - if you want to show a confirmation before the update, this holds the text to display. If absent, there will be no confirmation dialogue. If the user chooses ‘cancel’, the script will revert the change and terminate. * data-alert="Some alert text": Optional – if you want to warn the user that the update cannot happen for some reason (the script will then revert the change and terminate). * data-cache="#myid2" : Optional - if you want to cache the (changed) value, this element stores it. * data-cache-prefix="Some prefix string" : Optional (requires data-cache) - a prefix to prepend the value stored in the cache This currently works with the following trigger elements: * select options * select page (single and multiple) * page list select (single and multiple) * asm select * page autocomplete (but note that data attributes must be set in the wrapper element - e.g. $myInputfield->wrapAttr() ) * checkboxes (set attributes in wrapper as above) but not with: * toggle * checkbox * radio buttons (These partly work - the attributes need to be in the wrapper -, but doesn't work completely as wrapper 'value' attribute is not updated by PW (always 0) ) NOTE: If you are using this with other js scripts (e.g. in a module) that listen for events in the target, you must use event delegation (e.g. $(document).on("change","#myid", function(){}); NOT $("#myid").onchange(function(){}); ) because #myid is dynamic if it is inside the target) */ $(document).on('focusin', '[data-action="form-update"]', function(){ // get the value before the element is changed console.log("Saving value " + $(this).val()); $(this).data('val', $(this).val()); }).on('change','[data-action="form-update"]', function(event){ var prev = $(this).data('val'); var current = $(this).val(); console.log("Prev value " + prev); console.log("New value " + current); // if trigger element has data-confirm attribute, confirm or revert and exit var confirmText = $(this).data('confirm'); if (confirmText) { if (!confirm(confirmText)) { $(this).val(prev); return; } } // if trigger element has data-alert attribute, show alert and exit var alertText = $(this).data('alert'); if (alertText) { alert(alertText); $(this).val(prev); return; } // cache the value before proceeding (if data-cache set) var cache = $(this).data('cache'); var cachePrefix = ($(this).data('cache-prefix')) ? $(this).data('cache-prefix') : ''; $(cache).val(cachePrefix + current); var $form = $(this).closest('form'); var target = $(this).data('update-target'); console.log("Target is " + target); var method = $form.attr('method'); var action = $form.attr('action'); var data = $form.serialize(); var encodedName; // .serialize() will omit select elements that do not have a 'null' option (e.g. asm select, page list select) // or checkboxes with nothing selected // so find them and add empty parameters to the data string, otherwise the page field will not be updated $($form.find('select, input').each(function(index){ console.log('Select element no. ' + index + ' with name ' + $(this).attr("name") + ' has serialize = ' + $(this).serialize()); encodedName = encodeURI($(this).attr("name")) if (data.search(encodedName) === -1) { data += ('&' + encodeURI($(this).attr("name")) + '='); } })); console.log("Submitted data: " + data); if (!method) method = 'get'; if (!action) action = window.location.href; // If you want to fade the affected inputfields then assign the loading class to their wrappers with method wrapClass(loading) $(target).find('.loading').css({ display: 'block', opacity: 0.2 }).animate({ opacity: 1 }, 5000); // then send your request $.ajax(action, { type: method, // type used, not method, for older versions of jquery data: data, // you can also add an error handler here if required, in case the server returns an error on the request success: function (data) { // Initial ajax just returns an array with message. Need to GET the form data. $.ajax(window.location.href, { type: 'GET', cache: false, success: function (data) { // then just take the target, and replace it with the target div from the returned data console.log("Returned data: " + data); console.log("Updating html with: " + $(data).find(target).html()); $(target).html($(data).find(target).html()); } }); } }); });  
    • By MoritzLost
      This module allows you to integrate hCaptcha bot / spam protection into ProcessWire forms. hCaptcha is a great alternative to Google ReCaptcha, especially if you are in the EU and need to comply with privacy regulations.

      The development of this module is sponsored by schwarzdesign.
      The module is built as an Inputfield, allowing you to integrate it into any ProcessWire form you want. It's primarily intended for frontend forms and can be added to Form Builder forms for automatic spam protection. There's a step-by-step guide for adding the hCaptcha widget to Form Builder forms in the README, as well as instructions for API usage.
      Features
      Inputfield that displays an hCaptcha widget in ProcessWire forms. The inputfield verifies the hCaptcha response upon submission, and adds a field error if it is invalid. All hCaptcha configuration options for the widget (theme, display size etc) can be changed through the inputfield configuration, as well as programmatically. hCaptcha script options can be changed through a hook. Error messages can be translated through ProcessWire's site translations. hCaptcha secret keys and site-keys can be set for each individual inputfield or globally in your config.php. Error codes and failures are logged to help you find configuration errors. Please check the README for setup instructions.
      Links
      Github Repository and documentation InputfieldHCaptcha in the module directory (pending approval) Screenshots (configuration)

      Screenshots (hCaptcha widget)

       
       

       
    • By cosmicsafari
      Hi all,
      I have need to dynamically set InputFieldMultiSelect to  selected on page load based on the status of some items within a database table.
      However I keep running into issues when trying to do this via InputfieldSelect::setOptionAttributes()
      https://processwire.com/api/ref/inputfield-select/set-option-attributes/
      Going by the above it sounds like it should be pretty straight forward, and for certain values it seems to work but not when I wanted to set it to 'selected'.
      For example:
      $f->setOptionAttributes(1030,['foo' => 'test']); The above works as I would have wanted, in that it updates the option with the value 1030, to include the attribute foo="test"
      But the same code above edited to the following:
      $f->setOptionAttributes(1030,['selected' => 'selected']); Doesn't seem to do anything?
      I assume I'm missing something or trying to implement the 'selected' wrongly but I'm not sure how else I should approach this, any advice would be much appreciated.
       
×
×
  • Create New...