Soma Posted January 12, 2012 Share Posted January 12, 2012 I'm in need of a special inputfield with multiple input form fields. I created a little Inputfield extending InputfieldTextarea and using it for storing the values as json encoded string. Seeing an example of Ryan recently using this technique I went and tried to do a little custom Inputfield. I got it working so far with a little try and error, but wanted to have feedback, if there's anything done wrong or could be done better. I need this to store numeric values for the 12 months. These will be used to render a chart on page. So I first did a simple textarea and having each values on a new line, but wanted something more intuitive and convienient for the client to enter the values. (I know it would also be possible (and maybe better solution) to write a complete new Fieldtype/Inputfield, but I'm not really into it yet and would need some help. But this was kinda simple and does the job, only drawback is that it wouldn't work with selectors as it's stored as json in a text field in db.) Here's my code: <?php /** * ProcessWire Custom InputfieldMonths * * Inputfield that stores numeric values for the 12 months of a year. * */ class InputfieldMonths extends InputfieldTextarea { protected $months = array( "January" => "jan", "February" => "feb", "March" => "mar", "April" => "apr", "May" => "may", "June" => "jun", "July" => "jul", "August" => "aug", "September" => "sep", "October" => "oct", "November" => "nov", "December" => "dec" ); public static function getModuleInfo() { return array( 'title' => 'InputfieldMonths', 'version' => 100, 'summary' => 'Stores 12 integer values for months of a year', 'permanent' => false, ); } public function init() { parent::init(); } public function ___render() { $values = json_decode($this->value,true); $out = ''; foreach($this->months as $label => $name) { $out .= <<< _OUT <p> <label for='$name'>$label</label> <input id='$name' name='$name' value='$values[$name]'/> </p> _OUT; } return $out; } public function ___processInput(WireInputData $input) { foreach($input as $key => $val) { if(!in_array($key, $this->months) or $val === '') continue; if(!is_numeric($val)) return $this->error("Wrong format. Value '$val' is not numeric!"); } $months_values = array(); foreach($this->months as $month) { $months_values[$month] = $input[$month]; } $data = json_encode($months_values); if($this->value != $data) { parent::trackChange('value'); $this->value = $data; } return $this; } } 1 1 Link to comment Share on other sites More sharing options...
ryan Posted January 12, 2012 Share Posted January 12, 2012 I think for what you are trying to do: provide a simple solution to this particular need, it seems like a good solution. I like it. From a storage perspective, you could make it a little more efficient by using the month numbers (integers) in your encoded JSON rather than the month names, and then unset any blank values from the array before encoding it. This would ensure it's reduced to the smallest encoded format possible. Also, December is spelled wrong in your $months array at the top. Link to comment Share on other sites More sharing options...
Soma Posted January 13, 2012 Author Share Posted January 13, 2012 From a storage perspective, you could make it a little more efficient by using the month numbers (integers) in your encoded JSON rather than the month names, and then unset any blank values from the array before encoding it. This would ensure it's reduced to the smallest encoded format possible. You're right, thanks for the suggestions. But I need the blank values to be 0 for the chart, so I implemented a check that sets not filled in fields to 0. I know it would be possible to check for them in the output, but wanted to make it simple as possible. Thanks for pointing out the typo! Must have been sleeping... Link to comment Share on other sites More sharing options...
theo Posted February 17, 2018 Share Posted February 17, 2018 Thanks for this idea and example. This makes it super easy and economical to create multi-edit field types for settings which belong together. 1 Link to comment Share on other sites More sharing options...
theo Posted February 17, 2018 Share Posted February 17, 2018 Humm, it does not work in a repeater. It saves the same value for all items. What am I missing? Thank you. <?php /** * ProcessWire Custom InputfieldBSCol */ class InputfieldBSCol extends InputfieldTextarea { protected $cols = array("col" => "", "col-sm" => "sm", "col-md" => "md", "col-lg" => "lg", "col-xl" => "xl"); protected $sizes = array("", "auto", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"); public static function getModuleInfo() { return array( 'title' => 'InputfieldBootstrapCol', 'version' => 100, 'summary' => 'Stores Bootstrap 4 Columns Settings', 'permanent' => false, 'autoload' => false, 'singular' => false ); } public function init() { parent::init(); } public function ___render() { $values = json_decode($this->value, true); $brpval = $values['brp']; $bsizval = $values['bsiz']; $out = ''; $out .= '<select id="brp" name="brp">'; foreach ($this->cols as $key => $value) { $out .= "<option" . ($brpval == $value ? ' selected' : '') . " value=\"$value\">$key</option>"; } $out .= '</select>-'; $out .= '<select id="bsiz" name="bsiz">'; foreach ($this->sizes as $value) { $out .= "<option" . ($bsizval == $value ? ' selected' : '') . " value=\"$value\">$value</option>"; } $out .= '</select>'; return $out; } public function ___processInput(WireInputData $input) { $bs_col_options = array(); $bs_col_options['brp'] = $input['brp']; $bs_col_options['bsiz'] = $input['bsiz']; $colstr = 'col'; if ($input['brp'] != '') { $colstr .= '-' . $input['brp']; if ($input['bsiz'] != '') $colstr .= '-' . $input['bsiz']; } $bs_col_options['bcolstr'] = $colstr; $data = json_encode($bs_col_options); if ($this->value != $data) { parent::trackChange('value'); $this->value = $data; } return $this; } } Link to comment Share on other sites More sharing options...
theo Posted February 18, 2018 Share Posted February 18, 2018 Now I've got it. I feel like an idiot. I was thinking in terms of separate instances and separate pages, but forgot that all the input fields are in the same DOM tree. So they need distinct names . Actually it is all there with $attrs = $this->getAttributes(); $idstring=$attrs['id']; I just didn't know. Link to comment Share on other sites More sharing options...
theoretic Posted March 29, 2018 Share Posted March 29, 2018 @Soma, great example, thanks! However it's not very clear how to assign this (or similarly developped) custom inputfield to existing data field. Thanks for possible clarifications! Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now