9

I'm experimenting with JavaScript and Drupal forms. Currently I'm trying to make a button in the administration form of a module that will use JavaScript to append options to a select list. The problem I'm running into is that when I click the button, my JavaScript gets called but the whole form refresh. I've looked at the Forms API reference thinking there was some kind of attribute I can set on the button to stop it from but found nothing. Is there any way I can stop the button from refreshing the page or is this a dead end?

$form['#attached']['js'] = array(
  drupal_get_path('module', 'test').'/js/test.js',
);

$form['list'] = array(
  '#type' => 'select',
  '#options' => array(),
  '#attributes' => array(
    'name' => 'sellist',
  ),
  '#size' => 4,
);

$form['add_button'] = array(
  '#type' => 'button',
  '#value' => 'Add',
  '#attributes' => array(
    'onclick' => "add_to_list(this.form.sellist, 'Append' + this.form.sellist.length);",
  ),
);

//JavaScript
function add_to_list(list, text) {
  try {
    list.add(new Option(text, list.length), null) //add new option to end of "sample"
  }
  catch(e) {
    list.add(new Option(text, list.length));
  }
}

My final code:

<?php
function jstest_menu() {
  $items['admin/config/content/jstest'] = array(
    'title' => 'JavaScript Test',
      'description' => 'Configuration for Administration Test',
      'page callback' => 'drupal_get_form',
      'page arguments' => array('_jstest_form'),
      'access arguments' => array('access administration pages'),
      'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

function _jstest_form($form, &$form_state) {
  $form['list'] = array(
    '#type' => 'select',
    '#options' => array(),
    '#size' => 4,
  );

  $form['text'] = array(
    '#type' => 'textfield',
  );

  $form['add_button'] = array (
    '#type' => 'button',
    '#value' => t("Add"),
    '#after_build' => array('_jstest_after_build'),
  );
  return $form;
}

function _jstest_after_build($form, &$form_state) {
  drupal_add_js(drupal_get_path('module', 'jstest').'/js/jstest.js');
  return $form;
}

JavaScript
(function ($) {
  Drupal.behaviors.snmpModule = {
    attach: function (context, settings) {
      $('#edit-add-button', context).click(function () {
        var list = document.getElementById('edit-list');
        var text = document.getElementById('edit-text');

        if (text.value != '')
        {
          try {
            list.add(new Option(text.value, list.length), null);
          }
          catch(e) {
            list.add(new Option(text.value, list.length));
          }

          text.value = '';
        }

        return false;
      });
      $('#edit-list', context).click(function () {
        var list = document.getElementById('edit-list');

        if (list.selectedIndex != -1)
          list.remove(list.selectedIndex);

        return false;
      });
    }
  };
}(jQuery));
4

The most easy way to accomplish this is just return false in your javascript code:

function add_to_list(list, text) {
  try {
    list.add(new Option(text, list.length), null);
    return false;
  } catch(e) {
    list.add(new Option(text, list.length));   
    return false;
  }
}

or a better way is using behaviors:

Drupal.behaviors.some_action = function(context) {
  $('#id-button:not(.button-processed)',context)
  .addClass('button-processed').each(function() {

    //whatever you want here
    return false;
  });
}
  • 1
    Thanks for pointing me to behaviors, I'm reading up on it right now as a matter of fact. And for some reason returning false isn't working for me; the page is still refreshing =/. For a follow up question, how should you handle users that block/disable javascript? – Sathariel Dec 7 '11 at 6:48
  • If you put the button outside to a <form></form> tag this will not be submitted but this is not recommended, the more conventional way to do it is with javascript. If you form is still refreshing check if there is any other javascript is displaying a error or something like that. – Gnuget Dec 7 '11 at 7:22
  • Where to put Drupal.Behaviors code? in the javascript file? – user34776 Feb 4 '15 at 6:12
  • Yes, Take a look on this: amazeelabs.com/en/blog/drupal-behaviors-quick-how – Gnuget Feb 5 '15 at 5:32
7

the form button definition below works for me, the #after_build is useful for loading in javascript that can attach the click handler.

$form['add_button'] = array (
  '#type' => 'button',
  '#attributes' => array('onclick' => 'return (false);'),
  '#value' => t("Add"),
);

$form['#after_build'] = array('[module_name]_after_build');

Then my javascript that is loaded in a separate file by the after build function, looks something like:

Drupal.behaviors.[module_name] = function(context) {
  $('#edit-add-button').click(function() {
   ...Do something here
  });
};
  • After_build is not working for me. It throws me a Fatal error: Call to undefined function [module_name]_after_build(). If I define the method [module_name]_after_build() with empty body, form does not render. Can you clarify a bit more how to use it? – sumanchalki Jul 29 '13 at 8:26
  • Sorry, I didn't see this question... I assume you're replacing [module_name] with the actual name of your module? – Malks Aug 21 '13 at 22:58
  • $form['#after_build'] is for adding a server side (PHP) function - it's not for specifying post build javascript. api.drupal.org/api/drupal/… – Christian Mar 8 '16 at 5:25
3

You can just add the return false statement after your function call, inside the attribute line of the button form element:

'#attributes' => array(
   'onclick' => "add_to_list(this.form.sellist, 'Append' + this.form.sellist.length); return false",
),
  • I think a better option is to add an external event listener rather than putting it all in the inline onclick event. – Christian Mar 8 '16 at 5:26
0

Ideally, have a read into Drupal's own AJAX (or AHAH) form abilities. Really basic intro here http://drupal.org/node/752056

Otherwise, I'm surprised it is refreshing the page as it is just a 'button' not a submit or anything.

Does it need the javascript to return false, like on an link does to stop it jumping back to the top of the page?

  • Actually I was trying to avoid using AJAX since what I'm trying to do is mainly on the client-end. It isn't until that the form is submitted that the server needs the data. As far as returning things in the JavaScript, I've tried return true, false and null with no difference. – Sathariel Dec 5 '11 at 22:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.