Here's a code snippet that you can use to set the disabled attribute of a CCK field.
First, you need to create a small module containing the following code:
/**
* @file
* Custom module to set the disabled attribute of CCK fields.
*/
/**
* Implementation of hook_form_alter().
*/
function mysnippet_form_alter(&$form, $form_state, $form_id) {
if (isset($form['type']) && isset($form['#node'])) {
// Use this check to match node edit form for a particular content type.
if ('mytype_node_form' == $form_id) {
$form['#after_build'][] = '_mysnippet_after_build';
}
// Use this check to match node edit form for any content type.
// if ($form['type']['#value'] .'_node_form' == $form_id) {
// $form['#after_build'][] = '_mysnippet_after_build';
// }
}
}
/**
* Custom after_build callback handler.
*/
function _mysnippet_after_build($form, &$form_state) {
// Use this one if the field is placed on top of the form.
_mysnippet_fix_disabled($form['field_myfield']);
// Use this one if the field is placed inside a fieldgroup.
// _mysnippet_fix_disabled($form['group_mygroup']['field_myfield']);
return $form;
}
/**
* Recursively set the disabled attribute of a CCK field
* and all its dependent FAPI elements.
*/
function _mysnippet_fix_disabled(&$elements) {
foreach (element_children($elements) as $key) {
if (isset($elements[$key]) && $elements[$key]) {
// Recurse through all children elements.
_mysnippet_fix_disabled($elements[$key]);
}
}
if (!isset($elements['#attributes'])) {
$elements['#attributes'] = array();
}
$elements['#attributes']['disabled'] = 'disabled';
}
Explanation:
Setting the #disabled attribute of the element in form_alter doesn't work because the FAPI process handler of the CCK field won't transfer the #disabled attribute to its children elements. So we need to find a different method...
We can do this using our own #after_build handler, but here we cannot simple set the $element['#disabled']
attribute of the element. The reason is this attribute is transformed into $element['#attributes']['disabled']
by _form_builder_handle_input_element executes(), which is the format FAPI theme functions know about. However, _form_builder_handle_input_element executes() is executed before #after_build handlers are invoked, so our own handler needs to set the value as the theme functions expect. See form_builder().
Finally, we need to use a recursive function so that we can set the disabled attribute of all the FAPI elements that depend on the CCK field we're interested in. Think for example about a checkboxes element, etc.
Caveats:
Disabled attributes are not sent to the server with the form. The $_POST array will not have any value for disabled elements, and this may cause unexpected results. Also, if the element is required, will see the error 'field field is required.'.
Possible workaround:
Ok, now we're going to make a copy of the field that we want to disable, we will disable that one, and set the type of the original field to 'hidden'. I'm not sure if this technique will work for any kind of field, but here's a simple example that works:
Let's disable the node title. Well, to say something useful, let's imagine that our custom code also wants to assign a title to the node programmatically. In this case, we'll use the same code as above, but replacing the after_build function with this one:
/**
* Custom after_build callback handler.
*/
function _mysnippet_after_build($form, &$form_state) {
// Let's check the title exist.
if (isset($form['title'])) {
// Replace the element with an array that contains 2 copies.
$form['title'] = array(
'title' => $form['title'],
'_disabled_title' => $form['title'],
);
// Now, we change the type of the original field to 'hidden'.
$form['title']['title']['#type'] = 'hidden';
// Now, we can use our recursive function to set the disabled attribute
// or the field and all its own child elements. The title doesn't have children
// but maybe another field that you are interested in does.
_mysnippet_fix_disabled($form['title']['_disabled_title']);
}
return $form;
}
Now, we have a form where the 'visible' title element is disabled. The original field is hidden, which is the one that will be sent to the server with the form, and so we won't see the 'field is required' error. :)
Another possible workaround:
Here we're going to copy the '#default_value' attribute of the element to the '#value' attribute. Depending on the type of field, this method may also work, and it is actually a bit more simple.
/**
* Custom after_build callback handler.
*/
function _mysnippet_after_build($form, &$form_state) {
// Let's check the title exist.
if (isset($form['title'])) {
// Explicitly set the #value attribute of the element.
$form['title']['#value'] = $form['title']['#default_value'];
// Now, disable the element and its own children.
_mysnippet_fix_disabled($form['title']);
}
return $form;
}
Comments
Works great thanks
Works great thanks Markus
Does anybody know how to keep the default elements selected (i.e. a multiselect) with the element disabled?
Thanks
or how to change any other
or how to change any other attributes of the element? Like #default_value?
thanks!
From form_alter itself?
You should be able to alter #default_value attribute for any element in the form directly from hook_form_alter().
However, you should be sure that your module is loaded after the one that generates the form you intend to alter. You can do this by altering the weight of the module in the {system} table from the hook_install() of your module. See the fieldgroup module in CCK to see an example of this.
Doubt is the beginning, not the end of wisdom.
Thanks for this snippet--very
Thanks for this snippet--very useful.
I have a form with a cck field dependency:
field1: required
field2: required only if a value selected in field1 evaluates to TRUE
I set up both cck fields as required, but then based upon user input for field1 I hide and disable field2 using jquery.
Unfortunately, setting the attribute of field2 to "disabled" doesnt work, and the form fails validation because field2 is "still" required.
My question:
How would one use this technique in the context of javascript? How do I dynamically (client-side) set '#required' to FALSE?
thx
pp
'#required' is FormAPI attribute so you can't client-side
'#required' is FormAPI attribute so that's what you need to alter, server side. And this would require a different technique, I'm afraid. I would post in the forums so that the book page doesn't mix too much different stuff which end up hard to find later.
Doubt is the beginning, not the end of wisdom.
I have a slightly different
I have a slightly different need. I want to remove the title field without autonodetitle. Can we do the unset then?
I tried placing unset($form['title']['_disabled_title']['#title']); and unset($form['title']['title']['#title']); after $form['#after_build'][] = '_mymodule_after_build'; on mymodule_form_alter together with the above code, but each didn't do anything. The title is just disabled, but not disappear. Any hint?
Thanks
Update:
Placing either unset($form['title']); or $form['title'] = array(); on mymodule_form_alter did the trick. But I wonder if it's the right thing to do?
love, light n laughter
Trying to set #default_value
Not getting much success setting the default value...
(doing so because cck links don't allow a default of 'http://' as it's not a valid link)
Try to set #attributes = array('onClick' => 'javascript:fun(););
Please help me to set #attributes = array('onClick' => 'javascript:fun();');
I use drupal 5x and create cck field say payment with two radio buttons by cc and by check.
so i want to give a javascript function call on click of by cc button.
so i m not getting how to set this already created button using UI.
Workaround - use readonly instead of disabled
Another option, if you want the value submitted via POST but not editable is to use the readonly attribute instead of disabled.
Use the following in your after_build function
http://musketeers.me/ - Creating next-generation websites with precision and care.
http://www.phparch.com
yes readonly is the best work
yes readonly is the best work around. thanks.
yes readonly is the best work
Additionally you can style the readonly inputs for example with colored background in your themes stylesheet:
readonly & date or userlist fields
Thanks for the code. I got it to work for text fields. However some fields like: date, user list, select lists did not...
Please do you know the best way to make other fields readonly?
attributes disabled or readonly on cck field in hook_form_alter
THANKS for sharing this snippet. I would like to expound a bit that if your D6 cck field is within a field group, you'll need to reference the field to pass into this snippet by that field group path as in:
for the group name "group_quote_attr".
Also, to allow more flexibility and reuse, I added two more params, Attribute Name and Attribute Value to the recursive function and all places that call it:
--
http://drupaltees.com
80s themed Drupal T-Shirts
Not quite there
Thanks for taking the time and effort to cobble this code together.
I have a field set to accept up to 20 values. I would like to disable the input fields that already have a value while leaving the remaining empty input fields writable.
First i attempted to use your sample code. But I can't seem to get it to work. Perhaps you can assist?
I have taken your sample code and simply changed the 'mysnippet' to my own module and 'field_myfield' to my own field.
When i look at the resultant source through Firefox's 'page source', i can see the attribute 'disabled' set to the value of 'disabled'. However the field in question is not actually disabled. The field is populate by selecting a username through autocomplete.
Here is what i see in 'page source':
I tried the 'readonly' work
I tried the 'readonly' work around, but the attribute stills shows as "disabled".
The following is through Safari's View Source:
RE: Not quite there
I understand why you did it, but try taking the 'field_' prefixes off your field names. If you look at your $field variable you'll see that you're directly altering the object without any extra Drupaly syntax behind the scenes. (Do the same for any fieldset 'group_' prefixes).
In my case the object members look like this:
My version of the code (for content type pr) looks like this:
Hope this helps.
I'm wondering why this code snippet is necessary
My question is: Why the FAPI process handler of the CCK field won't transfer the #disabled attribute to its children elements? It's not possible?
I suggested a fix in nodereference_select module (in optionwidgets too) to pass down the #disabled attribute to the children elements.
In nodereference_select_process function we have the following code and comment:
Why couldn't we set the '#disabled' attribute here too??
Hacking CCK
Because that is where the form is built for all nodereference widgets. There are two things wrong with changing it there.
thanks!
I ran into this issue today. That is, needing to disable a couple of CCK fields when editing a node.
I would ordinarily do something like the following for the given $form_id in hook_form_alter():
After double and triple checking my syntax I became suspicious and thankfully found this thread.
Thanks so much for posting this workaround. It's not at all obvious and saved me a bunch of time.
Remove the Input Widget Entirely
Replace
_mysnippet_fix_disabled()
with the following:Disable a single option of an optionwidgets-buttons field
Is it possible to disable a single option from optionwidgets_buttons? The Allowed Values are a string instead of an array.
Disable a single option of an optionwidgets-buttons field?
Hi, I'm back here again.
I want to be able to either disable or remove an option. I've been able to write code to remove an option, but encounter the error 'An illegal choice has been detected'.
Only so many users are able to select an option. Once that max is reached the option is either to be disabled or removed. The above error is thrown because _form_validate is looking for the removed option.
#validated
The following should suppress the "An illegal choice..." message and allow the submission to continue.
However removing an option is potentially dicey because you risk losing a user's previous selection. I would reconsider your approach.
Hi Grayside. Thanks for your
Hi Grayside. Thanks for your code.
When I use it to remove a date field within a multigroup, I get an "invalid date" error on the field when the user tries to save changes.
I have a mutligroup with fields like: date, user list, select lists, etc, so I am trying to hide the group when user logged in is different for what the user list is showing. It works well with all the other fields, except the date field.
Please do you have any suggestions on how to get around this?
I also tried the read-only alternative code published in the thread. That works only on text fields, and does not work on : date, user list, select lists...
Thanks
I tried this solution but it
I tried this solution but it does not work for my case:
I would like on an episode of a node, display a field but we can not change it. This solution does that very well by cons when recording and publishing, the field is empty.
Example:
When creating the node I put in the field: Test
When editing the field is gray: Test
When recording the fields of publishing is empty!!! I would like my fields have the values: Test
Thank you for your help!
add javascript attribute to cck select form field
Seems like something that would have an easy solution for by now..
- I have a "select" dropdown form field.
- I would like to add a javascript function that fires "onChange" or "onSelect"
- ex: alert('good choice!');
It really takes 3 functions to do that?!?
try Ajax trigger module
try Ajax trigger module
Thanks for this
Solved my problem well. This was not an obvious solution.
B
subscribed
subscribed
is there any ready to use
is there any ready to use module for setting up attributes of cck text fields? i want to set disabled for some fields, filled by default or via php/ajax callback
Disabled field with value is erased
Hi all,
I found a solution for my problem here: http://stackoverflow.com/questions/1191113/disable-select-form-field-but...
I had two required cck fields, they were not submitted when i use the attribute "disabled" , so I used this "readonly" instead as referred in the above link..
$elements['#attributes']['disabled'] = 'disabled';=>
$elements['#attributes']['readonly'] = 'readonly';
disable date cck field
If you want to disable the date cck field, we will have to use the workaround#1 as mention about because the browser has to send the value back so the field validation will not display any error.
Note. the date cck field support multi-value, (the From date and To date). However, the code below only take care the From date
overkill?
Im I the only one that thinks it would be better to have cck refactored instead of solving things hacking? This should be an issue to cck module. Drupal, has a long way to go.
@bledari: Drupal has an
@bledari: Drupal has an extremely sophisticated Forms building & modifying system that is used for all modules. The reason modifying CCK this way is so complicated is because CCK itself is very complicated.
I agree BUT
I agree cck code is quite complicated, and I think it should for a core module BUT the module mantainers/creator could easily fix this I suppose. We can submit this as a feature request too. Has anyone done this? We cannot have a core module that cannot disable form elements without writing 20 lines of not obvious code, don't you think?
This is an excellent example,
This is an excellent example, and I fought like hell with this myself for a few days.
I came across another alternative that I figured I'd mention here in case others ran into similar - use hook_field_access.
It removes the field entirely, so default values aren't saved, so you still need to work around that, but to me it's a great deal easier than mucking about with the form, and there are no validation errors as a result of the field being missing.
For all those trying to set
For all those trying to set onclick, onfocus, onblur etc attributes to CCK fields, what you need to do is add your own _after_build function as described above, and then use the following syntax:
Note the ['value'] in the middle, something you wouldn't normally expect..
Enjoy.
and the select fields
and the select fields (combobox)?
they are disabled, but if i remove "disabled = disabled" using firebug, i can change them and submit the new values...
i tried:
but doesn't works...
thanks!
EASY MODE - Just Call it in UPercase to display.
<span style="text-transform: uppercase" type='text'>
TEXT TO DISPLAY IN UPERCASE HERE
</span>
AnY oNe CaN tYpE aNy MoDo In ThE InPuT fIeLd ThIs LiNe MaKe DiSpLaY aLl In UpErCaSe
<span style="text-transform: uppercase" type='text'>
ANY ONE CAN TYPE ANY MODE IN THE INPUT FIELD THIS LINE MAKE DISPLAY ALL IN UPERCASEfaster and furios....
Issue with some cck fields data
I have implemented the above code but when I submit form on node edit some of my cck fields lost its data. Here is my code
Is their any step I am missing?
Set 'readonly' OR 'disabled' attribute on base elements only
From all the ideas on this page (and some others as well, mostly cited here) I could put some code together that avoids the implications above. Like the loss of data that was inadvertently removed from the form structure.
(First of all be warned that disabling form inputs does not hamper forgery of the submitted data in the wild. Sensitive values, e.g. an order total, must always be stored or recalculated on the server side!)
In all the cases where you want form inputs to display their values purely informative however, the following code will hopefully also work for you.
My solution
I found a solution that worked for me, as none of the examples above met all my requirements. That is, I could set things as readonly, but the immutability was not enforced. You could just right click and edit with Firebug and save.
Making CCK fields read-only in Drupal 6
Only on nodes edit form
Hello,
First snippet from Markus works fine, but I would like to use it only on nodes edit form:
When you add a new node, you can fill the field, but you can't modify it after, on nodes edit form.
Any idea?
Thanks
Did anyone got this working
Did anyone got this working on node edit form only?
Thanks
Abhishek Sawant
Drupal Developer
For D7
Any solution for D7?
Drupal Theme developer.
Shivcharan
easy peasy lemon squeezy
Setting read-only field attribute for Drupal 7:
Replace above "custom" with your module, form_id and field definitions respectively.