Posts tagged with dynamic

Avatar-eric-london
Created by Eric.London on 2009-09-13
Tags:
New Comment
 
Please note: the content on this page orginates from ericlondon.com.
For some time now I've wanted to write a blog entry about using AHAH to create dynamically generated form elements. After a recent conversation at work regarding usability, I now had a real world example to create: how to use tiered taxonomy to dynamically generate a form. This code snippet will show you how to create a form that creates child select dropdowns based on the parent taxonomy term the user selects.

First I established a multi-tier taxonomy called "AHAH":


For this example I created a menu callback to display my initial form:
<?php
function helper_menu() {
  
  $items = array();
  
  $items['ahah-form'] = array(
    'title' => 'AHAH Form',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('_helper_callback_ahah_form'),
    'type' => MENU_CALLBACK,
    'access callback' => 'user_access',
    'access arguments' => array('access content'),
  );
  
  return $items;
  
}
?>


I then defined the page callback to show the initial form:
<?php
function _helper_callback_ahah_form() {

  // define an array to contain form elements
  $form = array();
  
  // define the top level vid
  $vid = 2;
  
  // fetch a tree of taxonomy elements
  $tree = taxonomy_get_tree($vid, 0, -1, 1);
  
  // loop though taxonomy and collect elements
  $options = array();
  foreach ($tree as $key => $value) {
    $options[$value->tid] = $value->name;
  }
  
  // create the first select dropdown input
  $form['select_1'] = array(
    '#type' => 'select',
    '#options' => $options,
    '#title' => t('Select 1'),
    '#size' => 5,
    '#multiple' => false,
    '#ahah' => array(
      'event' => 'change',
      'path' => 'ahah-form-callback',
      'wrapper' => 'wrapper-1',
      'method' => 'replace',
    ),
  );
  
  // pass the top level vid in the form
  $form['ahah_vid'] = array(
    '#type' => 'hidden',
    '#value' => $vid,
  );
  
  // create an empty form element to contain the second taxonomy dropdown
  $form['wrapper_1'] = array(
    '#prefix' => '<div id="wrapper-1">',
    '#suffix' => '</div>',
    '#value' => '&nbsp;',
  );
  
  // add a form submit button 
  $form['submit'] = array(
    '#value' => 'Submit',
    '#type' => 'submit'
  );
  
  return $form;
  
}
?>


The above form callback produces the following:


Next, I defined a callback to handle the AHAH page request:
<?php
// new menu item:
function helper_menu() {
  
  // ...
  
  $items['ahah-form-callback'] = array(
    'title' => 'AHAH Form Callback',
    'page callback' => '_helper_callback_ahah_form_callback',
    'type' => MENU_CALLBACK,
    'access callback' => 'user_access',
    'access arguments' => array('access content'),
  );
  
  // ...

  return $items;
  
}

// and, here's the AHAH callback used to create the new form elements:
function _helper_callback_ahah_form_callback() {
  
  // define a string variable to contain callback output
  $output = "";
  
  // pull the top level vid from the $_POST data
  $vid = $_POST['ahah_vid'];
  
  // pull the selected dropdown from the $_PODT data
  $parentVid = $_POST['select_1'];
  
  // loop through the taxonomy tree and fetch child taxonomies
  $options = array();
  $tree = taxonomy_get_tree($vid, $parentVid, -1, 1);   
  foreach ($tree as $key => $value) {
    $options[$value->tid] = $value->name;
  }
  
  // define the second tier select dropdown element
  $form['select_2'] = array(
    '#type' => 'select',
    '#options' => $options,
    '#title' => t('Select 2'),
    '#size' => 5,
    '#multiple' => false,
  );
  
  // rebuild form object and output new form elements 
  $output .= ahah_render($form, 'select_2');
  
  // render form output as JSON
  print drupal_to_js(array('data' => $output, 'status' => true));
  
  // exit to avoid rendering the theme layer
  exit();
  
}

// Lastly, here's a help function pulled from Nick Lewis's blog to alter the form
// see: http://www.nicklewis.org/node/967
// NOTE: based on poll module, see: poll_choice_js() function in poll.module
function ahah_render($fields, $name) {
  $form_state = array('submitted' => FALSE);
  $form_build_id = $_POST['form_build_id'];
  // Add the new element to the stored form. Without adding the element to the
  // form, Drupal is not aware of this new elements existence and will not
  // process it. We retreive the cached form, add the element, and resave.
  $form = form_get_cache($form_build_id, $form_state);
  $form[$name] = $fields;
  form_set_cache($form_build_id, $form, $form_state);
  $form += array(
    '#post' => $_POST,
    '#programmed' => FALSE,
  );
  // Rebuild the form.
  $form = form_builder($_POST['form_id'], $form, $form_state);

  // Render the new output.
  $new_form = $form[$name];
  return drupal_render($new_form); 
}
?>


The above code allows the user to select an option from the top level tier of taxonomy and the AHAH callback will generate the a select dropdown of the child taxonomies as shown below:



On form submission, you'll see that the options the user selected as stored in $form_state['values']['select_1'] and $form_state['values']['select_2']


Avatar-eric-london
Created by Eric.London on 2008-10-24
Tags:
New Comment
 
Please note: the content on this page orginates from ericlondon.com.
In this code snippet I'll explain how to create a menu item that has a dynamic title.

<?php
// define hook_menu to create menu item
function MYMODULE_menu() {
  $items = array();
    
  $items['MY/PAGE/URL/%'] = array(
    'page callback' => 'MY_PAGE_CALLBACK_FUNCTION',
    'title callback' => 'MY_PAGE_CALLBACK_TITLE_FUNCTION',
    'title arguments' => array(3), 
    'type' => MENU_CALLBACK, 
  );

  return $items;
}

// define title callback function
function MY_PAGE_CALLBACK_TITLE_FUNCTION($arg) {
  return "My dynamic title: " . $arg;
}
?>


In the above example, if you browsed to the URL: MY/PAGE/URL/blah-blah-blah, you'd have a page title of: My dynamic title blah-blah-blah. In a more applicable example, you might need to pass the node id to the callback function and then return: $node->title;

Check out the documentation on wildcard loader arguments for more advanced options.
Avatar-eric-london
Created by Eric.London on 2008-08-27
Tags:
New Comment
 
Please note: the content on this page orginates from ericlondon.com.
Taxonomy is a great way of categorizing your content, and in this case we'll take it a step further to organize your content and create a dynamic layout. In a recent situation, we created a taxonomy category for a given node type and assigned 4 terms to the category. The node type contained an image field and a description. We wanted to show a view all the node images, but categorized by taxonomy term. I thought the best way to accomplish this was to get a list of all the taxonomy terms, loop through them, pass the term ID as an argument to a view, and output each view's html dynamically. In the following code snippet, I created a module that generates a block [see below]

When creating your view, make sure you add an argument for "Taxonomy: Term ID". In my example, I selected "Use empty text" for the default argument option to prevent taxonomy terms from being shown if they do not have any matching nodes.

<?php
function MYMODULE_block($op='list', $delta=0) {
  $block = array();
  switch ($op) {
    case 'list':
      $block[0]['info'] = t('MYBLOCKTITLE');
      return $block;
      break;
    case 'view':
      $block['subject'] = NULL;
      $block['content'] = NULL;
      $block_content = "";
      
      // define vocab name
      $vocabName = 'MYCATEGORYNAME';

      // define view name
      $viewName = 'MYVIEWNAME';

      // define node type
      $nodeType = 'MYNODETYPE';

      // get vocabularies for this node
      $vocabs = taxonomy_get_vocabularies($nodeType));      
      
      // ensure vocabs exist
      if (count($vocabs)==0 || !$vocabs) return $block;

      // loop through vocabs and look for matching name
      foreach ($vocabs as $k => $v) {
        if ($v->name == $vocabName) {
          $vocabID = $v->vid;
          break;
        }
      }

      // ensure vocabID exists
      if (!$vocabID) return $block;

      // get vocab term tree
      $tree = taxonomy_get_tree($vocabID);

      // loop through tree and collect term IDs
      $termIDs = array();
      foreach ($tree as $k => $v) {
        $termIDs[$v->tid] = $v->name;
      }

      // loop through term IDs and create views html
      foreach ($termIDs as $k => $v) {

        // get view object
        $view = views_get_view($viewName);  

        // ensure result is an object
        if (!is_object($view)) continue;

        // create view html
        $viewHtml = views_build_view('block', $view, array($k), FALSE, $view->nodes_per_block);

        if (strlen($viewHtml)) {
          // show the taxonomy term name in an <h3>
          $block_content .= "<h3>$v</h3>";

          // add the view html to the block
          $block_content .= $viewHtml;
        }

      }

      $block['content'] = $block_content;
      return $block;
      break;
  }
  
}
?>


The result will resemble the following structure...

Taxonomy Term 1
[node] [node] [node]

Taxonomy Term 2
[node] [node] [node]

Taxonomy Term 3
[node] [node] [node]

Avatar-eric-london
Created by Eric.London on 2008-06-19
Tags:
New Comment
 
Please note: the content on this page orginates from ericlondon.com.
When creating a theme, it's important to keep your layout flexible in order to avoid wasted space. Here's a quick tutorial to show you how to vary theme layouts based on the contents of a region. Consider a common layout that contains 3 columns: sidebar_left, content, and sidebar_right. If the sidebar_right region did not have any blocks assigned to it, you could conserve valuable space by revising your theme layout using CSS and theme variables.

The first thing to do is add a variable to the page.php.tpl scope of your theme. In your template.php file, add a function called _phptemplate_variables. The following code checks the currently assigned variables to see if html has been assigned to the regions. If the region is empty, a variable will be passed to the theme containing CSS class selectors.

<?php
function _phptemplate_variables($hook, $vars=array()) {
  switch($hook) {
    case 'page':
      $layoutClasses = array();
      if (!$vars['sidebar_right']) $layoutClasses[] = 'noSidebarRight';
      if (!$vars['sidebar_left']) $layoutClasses[] = 'noSidebarLeft';
      $vars['layoutClasses'] = implode(' ', $layoutClasses);
      break;
  }
  return $vars;
}
?>


Next, in your page.tpl.php, locate the div in your layout that your like to conditionally change. Add the following code to add the CSS class selectors as necessary.

<?php
<div id='layoutContent' class='<?php print $layoutClasses; ? >' >
  BLAH BLAH BLAH
</div>
?>


Last, you can add CSS to revise your layout. In this case, I'll change the width of my divs.


#layoutContent {
  width: 500px;
}

#layoutContent.noSidebarRight {
  width: 750px;
}

#layoutContent.noSidebarLeft {
  width: 750px;
}

#layoutContent.noSidebarLeft.noSidebarRight {
  width: 1000px;
}