schwarzdesign Posted February 10, 2021 Share Posted February 10, 2021 I'm trying to disable a specific field only when it is displayed on a user's profile edit page. I have worked out the following solution, but it's shaky and I'm looking for a better approach: // disable the member type field when members edit their own profile wire()->addHookBefore('InputfieldPage::render', function (HookEvent $e) { $inputfield = $e->object; $field = $inputfield->hasField; $user = $inputfield->hasPage; $process = wire('process'); // only handle the u_type field if ($field->name !== 'u_type') return; // only for profile edits if (!($process instanceof ProcessProfile)) return; // only for regular members without additional access if ($user->isSuperuser() || $user->hasRole('editor')) return; // get the inputfield the InputfieldPage is delegated to (InputfieldRadios) $delegatedInputfield = $inputfield->getInputfield(); // get all available options $optionKeys = array_keys($inputfield->getInputfield()->getOptions()); // build an array with option id => attributes maps (this is the format expected by InputfieldRadios) $optionAttributes = array_combine( $optionKeys, array_map(fn($o) => ['disabled' => 'disabled'], $optionKeys) ); // add the attributes to the delegated inputfield to disable all options $delegatedInputfield->addOptionAttributes($optionAttributes); }); What bugs me about this: Seems overly complicated, isn't there a better way than going through the delegated inputfield and then setting the attribute manually for all options? Like a global disabled switch on InputfieldPage? The hook is dependent on the type of delegated inputfield and might break if it's switched to something else. This only sets the HTML disabled attribute, so it's easy to bypass. Of course I could add backend validation separately, but I would prefer a "unified" solution. Though for my use-case the backend validation is not that important, it's more about UX. By the way, just setting the field to hidden does not work in this case, because a couple of other fields have show_if dependencies on the field I'm trying to disable, and those don't seem to work when the field is not rendered at all. Any of you know a better approach? Thanks! Link to comment Share on other sites More sharing options...
Robin S Posted February 13, 2021 Share Posted February 13, 2021 On 2/11/2021 at 5:31 AM, schwarzdesign said: By the way, just setting the field to hidden does not work in this case, because a couple of other fields have show_if dependencies on the field I'm trying to disable, and those don't seem to work when the field is not rendered at all. This is the crux of the issue. If the user shouldn't be able to edit a field then you don't want it included in the ProcessProfile form, but as you say this causes issues with inputfield dependencies. My suggestion is: 1. Only include editable fields in ProcessProfile. 2. Remove the showIf condition when the dependent fields appear in ProcessProfile. 3. Implement the same showIf logic to determine which fields are editable in ProcessProfile. Example... In this case I have fields text_1, text_2 and text_3 in the user template. The text_2 and text_3 fields have the showIf condition "text_1=foo". But I don't want the user to be able to edit text_1 in ProcessProfile so I disable that field in the ProcessProfile module settings: In /site/ready.php: $wire->addHookBefore('ProcessProfile::execute', function(HookEvent $event) { /** @var ProcessProfile $pp */ $pp = $event->object; // The fields that have a showIf dependency on a field not editable in ProcessProfile $dependent_fields = ['text_2', 'text_3']; // If dependency condition not met, remove dependent fields from the ProcessProfile editable fields if($event->wire()->user->text_1 !== 'foo') { $pp->profileFields = array_diff($pp->profileFields, $dependent_fields); } // Remove showIf condition from dependent fields $event->wire()->addHookAfter('Field::getInputfield', function(HookEvent $event) use ($dependent_fields) { $inputfield = $event->return; if(!in_array($inputfield->name, $dependent_fields)) return; $inputfield->showIf = ''; }); }); 1 Link to comment Share on other sites More sharing options...
schwarzdesign Posted February 16, 2021 Author Share Posted February 16, 2021 @Robin S Good idea, thanks! The only problem I have with that solution is that it's hardcoded and there's no indication on the backend about the modification. This makes it harder to change fields, dependencies etc later on and it might cause problems if someone works on the site who doesn't know about that hook. So while it will solve this problem well, I'm worried it will cause others down the line. Of course, the same thing can be said about my hook above which just disables the field ? Another thing is that I would like the fields to be visible, just not editable, like a readonly field. So removing them entirely is not an option in this case. Though I will consider this approach for similiar problems, so thanks! 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