I am using Form API, can I display textfields on the same line, to the right of their accompanying title? The default is that I have the title on one line and the input area on the row below. I'd like them on the same row. Could you help? Thanks.

Comments

marcvangend’s picture

A CMS like Drupal tries to separate function and presentation. The alignment of form items is presentation; I suggest that you use CSS to do this.

MihaiP-1’s picture

I followed the model described here:
http://drupal.org/node/262422

Can I just add some css in the code, or within one particular field such as the following?

$form['year_of_birth'] = array(
'#type' => 'textfield',
'#title' => "Year of birth",
'#description' => 'Format is "YYYY"',
);

If I add < br >'s in the #title, I can get a few empty rows between. I just cannot place the two on the same row.

marcvangend’s picture

CSS is not added in the code, it is added in CSS files. Don't use the form API for styling (and that includes <br>). Try to add float:left to your field title's CSS rules.

MihaiP-1’s picture

Can I write html between the input blocks? I am thinking of putting all these fields in a table.

marcvangend’s picture

I'm starting to repeat myself... Use CSS! No offense, but serious web developers stopped using tables for layout 5 years ago. Look here if you don't know how to do it: http://www.dynamicdrive.com/style/csslibrary/item/css-tableless-form/

MihaiP-1’s picture

Ok, but how can I make my module listen for what I tell him in css?

xxx_frm.css
=========

.cssform textarea{
width: 250px;
height: 150px;
}

xxx_frm.module
===========


$form['text'] = array(
'#type' => 'textarea',
'#title' => t('A place to insert text'),
'#required' => FALSE,
'#rows' => 2,
'#cols' => 40,
);

I also have this Drupal invoke in my module:

function xxx_init(){
$path = drupal_get_path('module', 'xxx');
drupal_add_css($path .'/xxx.css', 'module', 'all', FALSE);
}

keva’s picture

the rendered page should find the correct CSS. If it's not working, either the module isn't invoking it right, or perhaps the CSS rule isn't specific enough. See Specificity at http://htmlhelp.com/reference/css/structure.html#cascade

I don't invoke CSS from a module (due to my limited knowledge); I just add what I need to the style.css file and label it accordingly.

Here's a similar example for putting 2 Ubercart elements ("add to cart" and the submit button) on the same line:

/* STORE PRODUCTS */

.productinfo .form-item label {
float: left;
padding-right: 10px;
}

.productinfo .form-submit node-add-to-cart {
float: right;
}

If you're not using them, I recommend Firebug and Web Developer toolbar plugins for Firefox

I just noticed that you refer to the css file as xxx_frm.css and invoke it with xxx.css. I realize those are not the real names, but could it be simply that you're not invoking the right file?

MihaiP-1’s picture

I am trying to understand, but unfortunately I am stumbling at this for days, without managing to see any formatting working on my computer.

Let's have a look at this module. All I need is to have the textfield next to the label, and not on two separate rows. Could you provide me with an example on how to achieve this? Thanks.

Code sample #1:

Here we start with a very basic form which we will expand upon in the upcoming code samples.


function my_module_menu() {
  $items = array();
  $items['my_module/form'] = array(
    'title' => t('My form'),
    'page callback' => 'my_module_form',
    'access arguments' => array('access content'),
    'description' => t('My form'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

// This function gets called when we visit 'my_module/form' page. It will generate
// a page with our form on it.
function my_module_form() {

  // We build the form by calling the form builder function via the
  // drupal_get_form() function which takes the name of our form builder
  // function as an argument. We return the results to display the form.
  return drupal_get_form('my_module_my_form');

}

// This function is what we call the "form builder". It builds the form.
// Notice it takes one argument, the $form_state
function my_module_my_form($form_state) {
   
    // Here is our first form element. It's a textfield with a label, "Name"
  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
  );
  return $form;
}
marcvangend’s picture

I don't want to be rude, but can you please read and try to understand what we're saying here? Both Zelavi and I are telling you to use CSS, but you keep posting php code.

Maybe I should make myself even clearer: Stop trying to do this with the forms API! This is not done in your module; layout is done in your theme. Do you see that text editor with your module's php code on your comupter? Close it! OK, now open your site in firefox, go to the right page and open the firebug panel. Point firebug at the form element you want to change, inspect it's CSS and change the CSS in your theme's CSS files until it looks good. It's not difficult. Trust me.

MihaiP-1’s picture

Ok, to make this clear. I want to use form API, then add a css file or something as I can't believe form apis to be so inflexible as to not allow displaying the label and the textfield on the same line. I posted just the php, as I didn't find out how to integrate css (your previous example was a html with css that I didn't know how to translate into my module). All I need is a very simple example on how to add a css file or something (at this point I'll need a step-by-step process as to what file do I need to create, how to name it, how to link it with my form api module and so on).

I have: my_module.info
my_module.module (the one I posted)
as described here: http://drupal.org/node/262422

I use Drupal version 6.

marcvangend’s picture

Better believe it: the form API does not control the placement of labels. But that's not inflexibility; that is what they call 'the separation of behaviour and presentation', which is one of the fundamental concepts of a CMS like Drupal. By separating them, you can change your form without losing styling, of change the styling without breaking the form. Now that is flexibility.

Your theme already has CSS files; you don't need to add or integrate new ones. You can add css rules to your theme's css files to change the appearance of your site. If you're not thinking 'sure, I can do that' right now, then read a theming tutorial (http://drupal.org/node/221881) and/or a CSS tutorial (http://www.tizag.com/cssT/).

If the classes in your source code do not suffice as css selectors, you can assign extra classes using the #attributes property (http://api.drupal.org/api/file/developer/topics/forms_api_reference.html...). Keep in mind that classes themselves do nothing; it's the CSS that 'reads' the classes and applies the styling.

marcvangend’s picture

You don't have to make your module listen. You can have your module add a css file to the page; you already have the code for that, I see. Then you look at the source code it produces and write your css accordingly.

MihaiP-1’s picture

Where can I see the extra code that is produced? I haven't noticed any difference after adding this part:

function xxx_init(){
$path = drupal_get_path('module', 'xxx');
drupal_add_css($path .'/xxx.css', 'module', 'all', FALSE);
}

marcvangend’s picture

You're posting code snippets, but how can I know what's happening if I can't see the complete picture? I advice you to follow a complete tutorial, from beginning to end, instead of trying to copy-paste small bits and asking us why it doesn't work. Maybe I'm wrong (I hope I am!), but I get the feeling that you're not trying to learn how it really works - you just want to get it running with a minimum of effords.

MihaiP-1’s picture

That was the whole code. And I am stucked with this for days. I only asked how I can do this, and while I do appreciate your way of making me get the big picture, I also like to have a question answered while I am learning. I tried a lot myself, otherwise I wouldn't be here.

mistresskim’s picture

...the form API does not control the placement of labels.

Not true. All form elements get "themed" via the theme_form_element function, also copied below. If you look at the page source for your form in the browser, you can see the layout and ids correspond. And look at all those new lines!


function theme_form_element($element, $value) {
  // This is also used in the installer, pre-database setup.
  $t = get_t();

  $output = '<div class="form-item"';
  if (!empty($element['#id'])) {
    $output .= ' id="'. $element['#id'] .'-wrapper"';
  }
  $output .= ">\n";
  $required = !empty($element['#required']) ? '<span class="form-required" title="'. $t('This field is required.') .'">*</span>' : '';

  if (!empty($element['#title'])) {
    $title = $element['#title'];
    if (!empty($element['#id'])) {
      $output .= ' <label for="'. $element['#id'] .'">'. $t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
    else {
      $output .= ' <label>'. $t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
  }

  $output .= " $value\n";

  if (!empty($element['#description'])) {
    $output .= ' <div class="description">'. $element['#description'] ."</div>\n";
  }

  $output .= "</div>\n";

  return $output;
}

The good news is that just like any theming function in Drupal 6 you can override it by copying the above function to your module, and renaming it to take into account the particular form_element you want to control. So if you were trying to theme a textfield called 'nickname', (I think) your function would be called theme_nickname. Then you would just need to modify the function - maybe ditch the new lines and wrap stuff in a div which you can then control from your CSS file? Another option would be to use a hook theme function and a tpl.php file to override your entire form.

marcvangend’s picture

...the form API does not control the placement of labels.

Very true. As you have just shown yourself, it's the theming layer where you control the HTML output. Theme overrides are, just like CSS stylesheets, part of your theme - not part of your module.

mistresskim’s picture

Sure, but Drupal's API does. It was obvious from the comments above that the author wanted to know when and where Drupal inserts its native html. And how to override it. It's misleading to tell newbies (and I consider myself one) that fiddling with a CSS stylesheet is the ONLY way they can control output since if Drupal has already wrapped elements in new lines etc, their CSS will have no effect until they undo that to begin with. That is my point. Also...

Theme overrides are, just like CSS stylesheets, part of your theme - not part of your module.

Functions can be part of your module. If you're creating a custom form etc why would you not stick your theme/preprocess functions or hooks in your module? Isn't that why functions like hook_registry_alter exist? Likewise, there are many modules which come with their own CSS sheets. Views, Panels, Date...

Anyway the point is that there are ways you can touch and alter the form outside of a CSS stylesheet while still maintaining a separation of logic and presentation.

marcvangend’s picture

I agree completely with your final point; the fact you can alter forms and html-output without hacking into a module is a very important feature of Drupal. The way you speak of styling-by-css ("fiddling") almost sounds as if this method is inferior to theme overrides or drupal hooks. But of course, CSS is not better or worse, it just does something else. CSS does not control the output, it styles the output.

You're right that CSS is not the only way, but I think it's the first thing to look at it you want to change the appearance of your page. The author of the comments above wanted to place two elements next to eachother; typically something you can do with CSS, and definitately not something you can do with the form API. I only use theme overrides of hook_form_alter when the html outputs conflicts with the CSS. That's why I wanted the original author to look at CSS first and forget about the form API, at least for a while.

Of course theme functions and stylesheets can be part of your module, I should have chosen my words more carefully on that point. Theme overrides are part of your theme, theme functions are part of a module and css can be both. The point I wanted to make is: they are all part of the theme layer, not on the functional layer where the form API is.

MihaiP-1’s picture

Ok, so I have to delve into the Drupal theme layer and change a lot of code. I thought I can just add a css block referring to the name of a form field (I called it my_module.css and put it in the same directory):

.name {
width: 100px;
clear: left;
margin: 10;
padding: 5px 0 8px 0;
padding-left: 155px; /*width of left column containing the label elements*/
border-top: 11px dashed red;
height: 11%;
}
(this is the .css I added after using my_module.info and my_module.module from here: http://drupal.org/node/262422)

I played around with the syntax and variable naming in my .css file, but I couldn't inflict any change on the display (though the site crashed when I put random syntax).

marcvangend’s picture

I don't think it will be a lot of code, but yes, you will have to add some css rules. Do you have a test site online? If we can see the html output your custom module produces, it's easier to help you with the css.

MihaiP-1’s picture

The problem is I don't know how to apply a css rule. I created a css file and I tried this:

.module file
=========

  $form['recette_title'] = array(
  	'#type' => 'textfield',
	'#title' => t('Titre de votre recette'),
  	'#size' => 40,
  	'#maxlength' => 40,
  	'#required' => FALSE,
	'#prefix' => '<div class="recette_titlee">',
       '#suffix' => '</div>',
  );

.css file
======
.recette_titlee{
width: 100px;
clear: left;
margin: 10;
padding: 5px 0 8px 0;
padding-left: 155px; /*width of left column containing the label elements*/
border-top: 11px dashed red;
height: 11%;
}

I want to see some red coloring or borders or something, but my module doesn't listen on css. Shouldn't this code be enough to accomplish this (apart from some errors that I hope you can help me correct)?

MihaiP-1’s picture

I copied the whole html code on my local computer, and the fields are displayed properly, with the label and the textfield on the same row.

keva’s picture

so, are you saying you got it to work?

If not, are you using a theme that has a style sheet (default name is style.css)?
Can you put your .recette_titlee class in there and see if that works?

MihaiP-1’s picture

Well, not quite - so it was indeed Drupal who messed with my alignment; in the end I modified the .css of the main theme, and got some global modifications. I wasn't able to refer a particular field yet.