I want to create a form in Drupal 7 similar to what it is in the following link : https://bmicalculator.cc/?gclid=CIrvnaXv1MQCFQwnjgodvWgAlQ
Form should start with text "BMI Calculator", then 2 columns similar in link and then note text similar to "BMI can be inaccurate for people..."
I know little bit Drupal Form Api so that I can create form but how to display text at the top, how to create form in 2 columns and then again text after form.
I am new to Drupal and hence don't have deep understanding of how drupal works.
To display the text at top, use the #markup item in the form render array. You can then embed the html that you need in this markup.
For the two columns, use the #container type in your form render array. This allows you to wrap a <div> around the child elements. You can then float the div as needed.
So an example would be
$form = array(
/*
* ... form header info here
*/
'header' => array(
'#markup'=>'<h1> BMI Calc </h1>',
),
'col1'=>array(
'#type'=>'container',
'subitemA'=>array(
//some stuff
),
'subitemB'=>array(
//some stuff
),
'#attributes' => array(
'class' => array('class-name'), //use css to float left
//alternatively float left using style in this area
),
),
'col2'=>array(
'#type'=>'container',
'subitemA'=>array(
//some stuff
),
'subitemB'=>array(
//some stuff
),
'#attributes' => array(
'class' => array('class-name'), //use css to float left
//alternatively float left using style in this area
//NOTE: still float left, the divs will align as two columns unless
//screen space is too small, then it will stack responsively.
),
),
);
Hope this helps.
Related
I have a form that has two FieldGroups, and in one of the FieldGroups I have a SelectionGroup.
The SelectionGroup_Items show up in the form FieldGroup but the radio boxes to select one of the options doesn't show. If I remove the FieldGroup it then works again.
I've looked at the framework templates, and if I change the FieldGroup_holder.ss SmallFieldHolder to FieldHolder the radio boxes appear again and work correctly. I've tried following the templates to see which one isn't obeying the SelectionGroup but I keep getting lost.
Here's an example bit of code
$fields = FieldList::create(
FieldGroup::create(
TextField::create('Name', 'Name')
),
FieldGroup::create(
SelectionGroup::create(
'Test1or2',
array(
SelectionGroup_Item::create(
'Test1', array(
TextField::create('Test1', 'Test1')
),
'Test1'
),
SelectionGroup_Item::create(
'Test2', array(
TextField::create('Test2', 'Test2')
),
'Test2'
)
)
)
)
),
FieldList::create(
FormAction::create('submit', 'Submit')
)
You could add another fieldset then set it's attributes to id="hidden_field" aria-hidden="true". In the css document you could do the following.
#hidden_field{
display:none;
height:0;
width:0;
margin:0;
padding:0;
visibility: hidden;
}
This should hide SilverStripe Framework's query behavior.
In my own php forms I had random brackets appearing whenever someone submitted a new form numerous times under different part-id numbers. I used this approach to hide the random brackets on my site.
I'm doing a project for uni, and as a part of it I am translating some of the pages, and need them in RTL.
These text fields are declared in a class on a different file.
I've managed to set the calling page to RTL (using [html dir='rtl']), which moved all the elements to the right of the page, but the labels of the text elements are to their left, and aligned to the left of the page.
Using [html dir='rtl'] in this file had no effect.
These are the relevant parts of the code (I think):
$keywords = new Zend_Form_Element_Text('keywords' , array('size' => '30'));
$keywords->setLabel('Keywords from Abstract')
->addFilter('StripTags')
->addFilter('StringTrim')
->setDescription('Enter one or more keywords, separated by whitespace.')
;
// Definition of additional (almost identical) elements
$this->addElements(array(..., $keywords , ... ));
$this->setDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'dl', 'class' => 'search')),
array('Description', array('placement' => 'prepend')),
'Form'
));
How can i move the labels to the right of the text elements?
Note that I've tried changing the last line to say 'placement' => 'append' , which did not seem to change anything.
Thanks in advance
You can change position of label decorator this way:
$decorator = $keywords->getDecorator('Label');
if ($decorator) $decorator->setOption('placement', Zend_Form_Decorator_Abstract::APPEND);
Than change styles for proper form output:
form dd {display: inline-block; width: 60%;}
form dt {display: inline-block; width: 35%;}
I am sending data via ajax to my PHP callback function inside my custom module... Everything is working great. The problem I am having is: the html i am returning and rendering in the ajax complete funciton is composed of fieldsets which wont expand/collapse. Things i have tested :
1). If I render the same html ( fieldsets ) into one of the custom blocks in that same module, they work great, the collapse and expand.
2). I have tried including this inside the callback function,
drupal_add_js('misc/form.js');
drupal_add_js('misc/collapse.js');
inside the fieldset render array,
return array(
'#type' => 'fieldset',
'#title' => t($title),
'#attributes' => array(
'class' => $class,
),
'#attached' => array(
'js' => array(
'misc/form.js',
'misc/collapse.js',
),
),
);
The
$class
variable contains collapsed and collapsible. I have also tried using
#theme => 'fieldset'
Instead of #type => 'fieldset'
the javascript files
misc/collapse.js
misc/form.js
are already being included from a different function inside my module. And looking at the source of the page, are indeed being included to the head of the page.
This has to be related to bringing them in via ajax, I know when you bring elements into the document via ajax, in-order to set events for those new elements you have to use
$(document).on('event', 'class', function(){
//code here
});
and I am wondering if this could be the reason that the fieldsets wont collapse/expand.
If you get data with AJAX with jQuery once you have to use Drupal.behaviors like this:
Drupal.behaviors.MYBEHAVIOR = {
attach: function (context, settings) {
$('MYELEMENT.MYBEHAVIOR', context).once('MYBEHAVIOR', function () {
// Apply the MYBEHAVIOR effect to the elements only once.
});
}
};
See more at the js documentation https://drupal.org/node/756722
Background: In Drupal 7, I have created a form with CCK (aka the Field UI). I used the Field group module to create a fieldgroup, but I need it to be conditional, meaning it will only display depending on a previous answer.
Previous research: To create a conditional field, you can use hook_form_alter() to edit the #states attribute like so:
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'person_info_node_form') {
// Display 'field_maiden_name' only if married
$form['field_maiden_name']['#states'] = array(
'visible' => array(
':input[name="field_married[und]"]' => array('value' => 'Yes'),
),
);
}
}
However, there seems to be no way to use the States API for fieldgroups. One thing to note is that, while fields are stored in $form, fieldgroups are stored in $form['#groups'] as well as in $form['#fieldgroups']. I don't know how to distinguish between these, and with this in mind, I have tried to apply a #states attribute to a fieldgroup in the same manner as above. However, it only produces server errors.
Question: Is there a way to make a fieldgroup display conditionally using the States API or some alternative approach?
you have to use the hook_field_group_build_pre_render_alter()
Simply :
function your_module_field_group_build_pre_render_alter(&$element) {
$element['your_field_group']['#states'] = array(
'visible' => array(
':input[name="field_checkbox"]' => array('checked' => TRUE),
),
);
}
This works perfecly. If the group A is in an another group, do this
$element['groupA']['groupB']['#states'] etc....
You may need to add an id attribute if none exists:
$element['your_field_group']['#attributes']['id'] = 'some-id';
$element['yout_field_group']['#id'] = 'some-id';
Here's the simplest solution I came up with. There are essentially 2 parts to this: (1.) programmatically alter the display of the form, and (2.) use the GUI to alter the display of the content.
(1.) First, I used hook_form_alter() to programmatically create the conditional fieldset and add existing fields to it. The code is shown below.
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'FORM_ID_node_form') {
// programmatically create a conditional fieldset
$form['MYFIELDSET'] = array( // do NOT name the same as a 'Field group' fieldset or problems will occur
'#type' => 'fieldset',
'#title' => t('Conditional fieldset'),
'#weight' => intval($form['field_PARENT']['#weight'])+1, // put this fieldset right after it's "parent" field
'#states' => array(
'visible' => array(
':input[name="field_PARENT[und]"]' => array('value' => 'Yes'), // only show if field_PARENT == 'Yes'
),
),
);
// add existing fields (created with the Field UI) to the
// conditional fieldset
$fields = array('field_MYFIELD1', 'field_MYFIELD2', 'field_MYFIELD3');
$form = MYMODULE_addToFieldset($form, 'MYFIELDSET', $fields);
}
}
/**
* Adds existing fields to the specified fieldset.
*
* #param array $form Nested array of form elements that comprise the form.
* #param string $fieldset The machine name of the fieldset.
* #param array $fields An array of the machine names of all fields to
* be included in the fieldset.
* #return array $form The updated form.
*/
function MYMODULE_addToFieldSet($form, $fieldset, $fields) {
foreach($fields as $field) {
$form[$fieldset][$field] = $form[$field]; // copy existing field into fieldset
unset($form[$field]); // destroy the original field or duplication will occur
}
return $form;
}
(2.) Then I used the Field group module to alter the display of the content. I did this by going to my content type and using the 'Manage display' tab to create a field group and add my fields to it. This way, the fields will appear to be apart of the same group on both the form and the saved content.
Maybe you can try to look at the code of this module to help you find an idea.
I'm building a site with Drupal and I have a small problem. I'm rendering a form using hook_menu. The form renders fine and all is good. I am then adding some more markup to the page using hook_page_alter(). Hook_page_alter looks like this:
function renderer_page_alter(&$page) {
if(drupal_is_front_page()) {
$q = db_query('SELECT name, mname, number_of_instances FROM {event_type} ORDER BY number_of_instances DESC');
foreach($q as $event) {
$options['name'][] = $event->name;
$options['mname'][] = $event->mname;
}
$tri = array(
'#theme' => 'frontpage_canvas',
'#options' => $options
);
return $page['content']['triangles'] = $tri;
}
}
So in my local MAMP install, the content is displayed with the results from hook_page_alter() first then followed by the form. However, in the remote install, the order is reversed (with the submit button for the form at the top of the page and the rest of the content beneath it). The only difference between the installs (that I can think of) is that the remote install is Drupal 7.8 and the local one is Drupal 7.9.
I would like to have the remote install in the same way as the local one. Has anyone come across an issue like this before?
The basic structure of the rendered HTML is like this:
<div class=content>
//all the form information is in here
</div>
<div class=rendered>
//all the output from hook_page_alter() is here
</div>
EDIT: The issue is that for some reason, block.tpl.php is adding two divs:
<div id="block-system-main" class="block block-system first last odd">
<div class="content">
//My form markup is in here
</div>
</div>
//The hook_page_alter markup is in here.
So, is there any way to force Drupal to add the hook_page_alter markup to the same div as the form is being rendered in? Because the way it's being rendered at the moment, the #weight property doesn't affect the positioning.
Thanks,
The display order in render arrays is set using the #weight attribute, elements with a higher #weight will be rendered after those with a lower value.
If you want to force the content added in hook_page_alter() to be rendered at the top of the content area declare it like this:
$tri = array(
'#theme' => 'frontpage_canvas',
'#options' => $options,
'#weight' => -1000
);
or at the bottom of the content area:
$tri = array(
'#theme' => 'frontpage_canvas',
'#options' => $options,
'#weight' => 1000
);
You can also adjust the #weight for other elements that already exist in the $page array passed in to the function, so you have total control over the display order.