How do I send data to a template page on form submission? I am building a weather API in Drupal 7, and I am unable to send weather report to my custom template file. Everything is working fine but the result is not displayed; everything is working as expected except result display.

.info


name = BM Weather API Part 2
description = Display the current weather condition of a specific location
package = BM API
version = VERSION 
core = 7.x 


.module

&lt;?php
function BM_weather_API_part2_theme() {
  return array(
    'BM_weather_API_part2' =&gt; array(
      'template' =&gt; 'BM_weather_API_part2',
      'variables' =&gt; array('msg' =&gt; NULL),
    ),
  );
}


function BM_weather_API_part2_menu() {    
  $items['BM_weather_API_part2'] = array(
    'title' =&gt; 'Weather API - Part 2',
    'page callback' =&gt; 'BM_weather_API_part2_view',
    'access arguments' =&gt; array('access content'),
    'file' =&gt; 'BM_weather_API_part2.pages.inc',
  );

  return $items;
}


.inc

function BM_weather_API_part2_view() {
  $dis = drupal_get_form('BM_weather_API_part2_form');
  return $dis;
}

function BM_weather_API_part2_form() {
  $form['location_name'] = array(
    '#title' =&gt; 'Location',
    '#type' =&gt; 'textfield',
    '#description' =&gt; 'Enter Location Here.',
  );


  $form['submit'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; 'Get Weather Report',
    '#submit' =&gt; array('BM_weather_API_part2_get_weather_report'),
  );

  return $form;
}


function BM_weather_API_part2_get_weather_report($form, &amp;$form_state) {
  $loc_name = $form_state['values']['location_name'];

  if (ctype_digit($loc_name)) {
    form_set_error('BM_weather_API_part2_character_required', t('Please Enter Proper Location Name.'));
    return;
  }
  elseif ($loc_name == '') {
    form_set_error('BM_weather_API_part2_character_required', t('Please Enter Location Name'));
    return;
  }

  $freport =  get_weather_from_google($loc_name); 

  return theme('BM_weather_API_part2', array('msg' =&gt; $freport));
}


function get_weather_from_google($loc) {
  // $finalreport contains the final report coming from google
  return  $finalreport;
}


.tpl

print $msg;
Form submission handlers (in your case, BM_weather_API_part2_get_weather_report()) don't return any value. See user_login_submit(), and user_register_submit() as examples of form submission handlers.

What I would suggest for your form submission handler is the following:


Set $form_state['rebuild'] to TRUE, and $form_state['BM_weather_API']['weather_result'] to the value obtained from the weather service; this would cause the form builder to be called again.
At this point, the form builder should verify if the content of
$form_state['BM_weather_API']['weather_result'] is not empty, and show the output obtained from the weather service, for example using code similar to the following one.

// First case.
$form['result'] = array(
  '#theme' =&gt; 'BM_weather_API_part2',
  '#msg' =&gt; $form_state['BM_weather_API_part2']['weather_result'],
);


 

// Second case.
$form['result'] = array(
  '#markup' =&gt; $form_state['BM_weather_API_part2']['weather_result'],
);


In the first case, $form_state['BM_weather_API_part2']['weather_result'] is the value obtained from the weather service, which needs to be passed to the theme function; the code would cause the theme function to be called, and get the value of $form_state['mymodule']['weather_result] as value for the $msg variable used in the template file. In the second case, $form_state['BM_weather_API_part2']['weather_result'] is the value obtained from the theme function, which got the weather service's result.


The code I would write is similar to the following one.

.module

&lt;?php
function BM_weather_API_part2_theme() {
  return array(
    'BM_weather_API_part2' =&gt; array(
      'template' =&gt; 'BM_weather_API_part2',
      'variables' =&gt; array('msg' =&gt; NULL),
    ),
  );
}

function BM_weather_API_part2_menu() {    
  $items['weather/report'] = array(
    'title' =&gt; 'Weather API - Part 2',
    'page callback' =&gt; 'drupal_get_form',
    'page arguments' =&gt; array('BM_weather_API_part2_form'),
    'access arguments' =&gt; array('access content'),
    'file' =&gt; 'BM_weather_API_part2.pages.inc',
  );

  return $items;
}


.inc

function BM_weather_API_part2_form() {
  $form['location_name'] = array(
    '#title' =&gt; 'Location',
    '#type' =&gt; 'textfield',
    '#required' =&gt; TRUE,
  );

  if (!empty($form_state['BM_weather_API_part2']['weather_result'])) {
    $form['result'] = array(
      '#markup' =&gt; $form_state['BM_weather_API_part2']['weather_result'],
    );
  }

  $form['submit'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; 'Get the weather report',
    '#validate' =&gt; array('BM_weather_API_part2_form_validate'),
    '#submit' =&gt; array('BM_weather_API_part2_form_submit'),
  );

  return $form;
}

function BM_weather_API_part2_form_validate($form, &amp;$form_state) {
  if (BM_weather_API_part2_check_location($form_state['values']['location_name'])) {
    $form_state['BM_weather_API_part2']['weather_result'] = FALSE;
    form_set_error('location_name', t('Please enter a proper location name.'));
  }
}

function BM_weather_API_part2_form_submit($form, &amp;$form_state) {
  $form_state['BM_weather_API_part2']['weather_result'] = theme('BM_weather_API_part2', array(
    'msg' =&gt; BM_weather_API_part2_get_weather($form_state['values']['location_name']))
  );

  $form_state['rebuild'] = TRUE;
}

function BM_weather_API_part2_get_weather($loc) {
  // ...
}


I will add some notes about your code.


In the implementation of hook_menu(), the array keys are the paths associated with the menu callbacks; in your case, as you use $items['BM_weather_API_part2'], the URL for that menu callback would be http://example.com/BM_weather_API_part2 (replace example.com with the URL of your site). It is preferable a path like weather, or weather/report, which is similar to the paths used from Drupal, such as node/1, user/1/edit.
When defining a menu callback, you can use 'page callback' =&gt; 'drupal_get_form' and pass as first argument of "page arguments" the name of the form builder; there isn't the need to define a function such as BM_weather_API_part2_view(), whose only purpose is to call drupal_get_form().
The form submission handlers don't check if the submitted values are correct; that is a task for the form validation handlers. That is why I am using a form validation handler, in my example code.
If the users need to enter a value for a form field, then you can simply use '#required' =&gt; TRUE for that form field, as I did.
ctype_digit() returns TRUE when the parameter it gets is a string containing only digits. I am not sure that is what the user should input in your case, as a number is not what I would consider a location name. If the user really needs to enter a number, the description for the "Location" form field should say that, and it should also explain what type of input the form it is expecting (e.g. a zip code).
The first argument of form_set_error() is the form field ID. As you don't have any form field that uses "BM_weather_API_part2_character_required" as ID, form_set_error('BM_weather_API_part2_character_required', t('Please Enter Proper Location Name.')) is not highlighting any form field, which is part of the purpose of form_set_error(). In your case, you should use form_set_error('location_name', t('Error string')), as location_name is the form field ID for the field you are reporting an error.
All functions implemented in a module should be prefixed with the short name of the module (after an underscore, if the function is "private"); in this way, there isn't any collision between different modules, which is what happens if two different modules would define a get_weather_from_google() function.
If the template file just prints the value it gets between its variables, then there isn't the need of a template file, or a theme function; you just use code similar to the following one:

function BM_weather_API_part2_form_submit($form, &amp;$form_state) {
  $form_state['BM_weather_API_part2']['weather_result'] = BM_weather_API_part2_get_weather($form_state['values']['location_name']));
  $form_state['rebuild'] = TRUE;
}


I wrote the example code assuming that your template file does more than just printing a variable it gets, and you didn't show all the code for the template file; if the template file does only that, then the template file, and the theme function are not necessary.


As side note, if the short name of your module contains uppercase characters, you will have problems with hook_update_N() being executed. You should always use lower case characters in the short name of your module.