Federico Posted December 30, 2017 Share Posted December 30, 2017 Hi PW community, struggling to find a way to add custom action button fieldtype to each duplicates inside a repeater fieldtype, so for all repeater there will be a dedicated button to submit and post-elaborate related pages selection. This repeater fieldtype will be used in custom module, I thought Hooks will be my friends for this, but maybe I am wrong. Couldn't find any post for this, maybe someone could suggest a way to go Much appreciated, thank you vey much Link to comment Share on other sites More sharing options...
dragan Posted December 30, 2017 Share Posted December 30, 2017 Well, each item inside a repeater is a field. Since there are no button input fields you could choose from, you could try building something with FieldtypeRuntimeMarkup? https://modules.processwire.com/modules/fieldtype-runtime-markup/ 1 Link to comment Share on other sites More sharing options...
dragan Posted December 30, 2017 Share Posted December 30, 2017 Just tried it: it works Just follow the RuntimeMarkup instructions, and make sure you choose the wireRenderFile method. Add your new RM field to your repeater, and include something like <li class="Inputfield InputfieldSubmit Inputfield_submitSelection uk-width-auto uk-margin-top uk-grid-margin uk-first-column reloaded InputfieldRowLast" id="make-this-id-unique"> <div class="InputfieldContent uk-form-controls"> <button id="make-this-unique-too" class="ui-button ui-widget ui-corner-all ui-state-default" name="ditto" value="Submit / Send x" type="submit"> <span class="ui-button-text">Submit / Send x</span> </button> </div> </li> I guess you'll want to edit the IDs, and add data-attributes or hidden fields to do whatever you've got to do 1 Link to comment Share on other sites More sharing options...
bernhard Posted December 30, 2017 Share Posted December 30, 2017 hm... @dragan i guess the runtimemarkup field only has to return the "<button>" element (without the <li>, <div.InputfieldContent> and so on... 3 hours ago, Federico said: I thought Hooks will be my friends for this, but maybe I am wrong you are right see this post for example (and the following): and also this: https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/#using-internal-components-modules (scroll down to the buttons section) 2 Link to comment Share on other sites More sharing options...
Federico Posted December 30, 2017 Author Share Posted December 30, 2017 thanks both!! @dragan I've created a php file with that html code and included as wireRenderFile in RuntimeMarkup - it works as expected, so thanks for the hint. Perhaps the html code needs to be integrated with php variable to host related IDs of each buttons, so eventually all buttons IDs and other attributes reflect the related repeater field. What might be the drawback of this solution, if any? @bernhard, great tutorial there, hat off! as of the button, can you please tell how the option 2 could work in the case that: - repeater is a field associated to a template (so far so standard) - the edit to the repeaters field will be made from a custom module - then, how to implement the following in such scenario? $button = $this->modules->get('InputfieldButton'); $button->value = 'Open Page in Panel'; $button->attr('data-href', './my-info'); $button->addClass('pw-panel'); $out .= $button->render(); I mean, how to properly hook every repeaters in a module and add button accordingly? Feel like I miss the basis... Link to comment Share on other sites More sharing options...
dragan Posted December 31, 2017 Share Posted December 31, 2017 Great Obi-Wan @bernhard: Yes, of course. I was just quickly copy-and-pasting from Chrome inspector... wanting to do a quick "proof of concept". @Federico As the RM module docs mention, "The field's value is accessible from the ProcessWire API in the frontend like any other field, i.e. it has access to $page and $pages.". I also made hints in my example code where IDs are used, that this should be populated by your custom PHP code (make-this-id-unique). 1 Link to comment Share on other sites More sharing options...
Federico Posted December 31, 2017 Author Share Posted December 31, 2017 Thanks @dragan! as of the hook option, still I cannot find a way to hook each repeater, in order to append to them a button. I've tried this within "init()" $this->pages->addHookAfter('ProcessPageEdit::buildForm', $this, 'addButtons'); then something like this public function addButtons($event) { $page = $event->object->getPage(); if($page->template == "book2pdf"){ $form = $event->return; $accept = $this->modules->get('InputfieldSubmit'); $accept->attr('id+name', 'hook_accept_application'); $accept->class .= ' ui-priority-secondary head_button_clone'; $accept->attr('value', $this->_('Accept Application')); $form->insertBefore($accept, $form->get("id")); } } but it doesn't hook/output anything. Do you know what is the proper hook for getting each repeater one by one (then append a button to them)? this is my execute() code: public function ___execute(){ $editpage = $this->pages->get(2308); $ignorefields = array("title"); $form = $this->modules->get("InputfieldForm"); $form->method = 'post'; $form->action = './'; $fields = $editpage->fieldgroup; foreach($fields as $field) { if(in_array($field->name, $ignorefields)) continue; $inputfield = $fields->{$field->name}->getInputfield($editpage); $form->append($inputfield); } // the inputfields don't already have a submit button, so we'll add one. $submit = $this->modules->get("InputfieldSubmit"); $submit->name = "submit"; $submit->value = 'Save book'; // add the submit button the the form $form->add($submit); $out = ''; // process the form if($this->input->post->submit) { // now we assume the form has been submitted. // tell the form to process input frmo the post vars. $form->processInput($this->input->post); // see if any errors occurred if( count( $form->getErrors() )) { // re-render the form, it will include the error messages $out .= $form->render(); } else { // successful form submission, so populate the page with the new values. $editpage->of(false); // turn off output formatting before setting values foreach($form as $field) { //$editpage->set($field->name, $field->value); $editpage->set($field->name, $form->get($field->name)->value); } // save it $editpage->save(); $this->message("Book saved!"); $out .= $form->render(); } }/* if($this->input->post->ditto) { // now we assume the form has been submitted. // tell the form to process input frmo the post vars. $form->processInput($this->input->ditto); // see if any errors occurred if( count( $form->getErrors() )) { // re-render the form, it will include the error messages $out .= $form->render(); } else { // successful form submission, so populate the page with the new values. $editpage->of(false); // turn off output formatting before setting values foreach($form as $field) { $editpage->set($field->name, $form->get($field->name)->value); } $this->message("DITTO"); $out .= $form->render(); } }*/ else { $out .= $form->render(); } return $out; } Maybe the hook method itself is wrong... Link to comment Share on other sites More sharing options...
bernhard Posted December 31, 2017 Share Posted December 31, 2017 hey @Federico 45 minutes ago, Federico said: but it doesn't hook/output anything. Do you know what is the proper hook for getting each repeater one by one (then append a button to them)? i didn't read all your code but I would hook the inputfield's render method of the field that is inside the repeater. or you create a runtime markup field with your code. that might be easier. the only thing you have to take care of when hooking yourinputfield::render() is that the $field->name is not the field's name only but it has some appended or prepended string (repeater name or id, not sure at the moment... you can easily check this with tracy). always start without any additional checks/ifs/returns and then continue step by step until you get where you want, for example this in your /site/ready.php: $wire->addHookAfter('Inputfield::render', function($event) { $field = $event->object; bd($field->name); }); then you can modify the hook to only execute when needed (like hooking InputfieldText instead of the Inputfield base class, doing a return when the field name does not match...). i think @Robin S came up with a good solution how to check for the right field name inside repeaters but i can't find where he mentioned it in the forum. this is another way of checking that i used, but maybe robin can show us the better way Link to comment Share on other sites More sharing options...
Federico Posted December 31, 2017 Author Share Posted December 31, 2017 Thanks @bernhard, we will see if any better implementation could fit this scenario. In the meantime, I've been playing around the runtime fieldtype as suggested by @dragan, and I think for now this is the quickest solution. btw, to get unique IDs to each button (within the Details tab), this worked for me $idUnique = $this->name; return ProcessWire\wireRenderFile('runtimeButton.php', array('idUnique' => "$idUnique")); Link to comment Share on other sites More sharing options...
dragan Posted December 31, 2017 Share Posted December 31, 2017 $wire->addHookAfter('Inputfield::render', function (HookEvent $event) { $field = $event->object; if (substr($field->name, 0, 13) === 'repeater_item') { $page = $event->arguments(0); $id = str_replace('repeater_item_', '', $field->name); $submitID = "submitRepeaterItem_$id"; $form = wire('modules')->get("InputfieldForm"); $submit = wire('modules')->get("InputfieldButton"); $submit->attr("value", "Edit this repeater item as page"); $submit->attr('data-href', wire('config')->urls->admin . "page/edit/?id=$id"); $submit->addClass('pw-panel'); $submit->addClass('uk-margin-left'); $submit->attr("id+name", $submitID); $form->append($submit); $myForm = $form->render(); $event->return .= $myForm; } }); I've got this in ready.php... seems to work. 2 1 Link to comment Share on other sites More sharing options...
Federico Posted January 2, 2018 Author Share Posted January 2, 2018 Hi @dragan, late here just to say that after some play around hooks, I couldn't find any other way (better) than your nice snippet above. Indeed, your seems to be the most appropriate way to append buttons to each repeater (my case is in custom admin module but it involves just few changes). I will mark this tread as solved but other solution are still welcomed Beside this, I've found that the InputfieldButton doesn't have any clean option to manage the html target="_blank", as these are the options the module allows $repeaterBtn = $this->modules->get("InputfieldButton"); $repeaterBtn->attr("value", "Generate something"); $repeaterBtn->attr("type", $submitID); $repeaterBtn->attr("id+name", "btn"); $repeaterBtn->attr("data-href", "customData"); $repeaterBtn->addClass("customClass"); Maybe someone has quick n' dirt solution, probably like this one? $this->pages->addHookAfter('Inputfield::render', function (HookEvent $event) { $field = $event->object; if ($field->name === 'btn') { // add target blank } }); Link to comment Share on other sites More sharing options...
dragan Posted January 2, 2018 Share Posted January 2, 2018 Just use InputfieldMarkup instead Link to comment Share on other sites More sharing options...
bernhard Posted January 2, 2018 Share Posted January 2, 2018 $wire->addHookAfter('InputfieldText::render', function($event) { $field = $event->object; if($field->name != 'title') return; $repeaterBtn = $this->modules->get("InputfieldButton"); $repeaterBtn->attr("value", "Generate something"); $repeaterBtn->attr("type", $submitID); $repeaterBtn->attr("id+name", "btn"); $repeaterBtn->attr("href", "/admin/page/edit/?id=1"); $repeaterBtn->attr("target", "_blank"); $repeaterBtn->addClass("customClass"); $event->return .= $repeaterBtn->render(); }); btw: panels are a great alternative for new browser tabs: https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/#using-internal-components-modules 1 Link to comment Share on other sites More sharing options...
Federico Posted January 2, 2018 Author Share Posted January 2, 2018 @bernhard thanks that's awesome! I was trying that attr() but eventually I discovered that if the button type="if differs from just button here, the _blank will not work" $repeaterBtn = $this->modules->get("InputfieldButton"); $repeaterBtn->attr("value", "Generate something"); $repeaterBtn->attr("type", "button"); // IF DIFFERS FROM JUST "button", IT WILL NOT OPEN NEW BROWSER TAB! $repeaterBtn->attr("id+name", "btn"); $repeaterBtn->attr("href", "/admin/page/edit/?id=1"); $repeaterBtn->attr("target", "_blank"); $repeaterBtn->addClass("customClass"); $event->return .= $repeaterBtn->render(); Thanks again both! 1 Link to comment Share on other sites More sharing options...
Federico Posted February 25, 2018 Author Share Posted February 25, 2018 Hi there, sorry for raising this up, but I think it is not entirely correct to leave this as "solved", because I've just discovered that all the hook code above will actually add new <form> tag for each repeater, leading to a code mess and nested forms.. $this->pages->addHookAfter('Inputfield::render', function (HookEvent $event) { //$page = $event->arguments(0); $field = $event->object; //substr takes the first 13 letters to match the repeater_item if (substr($field->name, 0, 13) === 'repeater_item' && $this->page->name === 'book') { $id = str_replace('repeater_item_', '', $field->name); $form = wire('modules')->get("InputfieldForm"); $repeaterBtn = wire('modules')->get("InputfieldButton"); $repeaterBtn->attr("value", "Generate Brochure in panel"); $repeaterBtn->attr("type", "button"); $repeaterBtn->attr("id+name", "button_form_$field->name"); $repeaterBtn->attr("data-href", "./testa/"); $repeaterBtn->addClass("ui-priority-secondary "); $repeaterBtn->addClass('pw-panel button_export2pdf'); $form->append($repeaterBtn); $myForm = $form->render(); $event->return .= $myForm; } }); by calling Inputfieldform here, eventually the module will load these new button in a new form tag, the latter nested into the main form tag room for improvement? 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