Dynamic forms in Icinga Web 2

In my last internal project of NETWAYS I had to build an Icinga Web 2 module, which should use a dynamic form. Specifically, there should be several dropdown menus, which evaluate the value of the previous selected dropdown menu and based on that, it fills a new dropdown menu and so on. There are two approaches that can be used, which I will explain below.

The classic (bad) approach

The first possibility that comes to mind is to use AJAX to call various actions in Icinga Web 2. These in turn, have code that handles the value of the previously selected dropdown-value and populates it to the other dropdown menu. Since Icinga Web 2 follows an MVC (model, view, controller) pattern, a controller script is needed for management and evaluation and a view script for displaying it on the frontpage. Furthermore, the AJAX request requires its own module.js file where the JavaScript code is stored. In addition, you have to include CSS, so that the form can be also displayed nicely.

So it’s a very very laborious approach!

The correct approach

As mentioned above, Icinga Web 2 is an MVC, so it brings it own so-called "ConfigForm views" that already provide all the stuff you need: CSS, JavaScript and HTML. The best part is, that this is super easy to implement and the framework does all the work from the "bad approach" on it's own. You can give a Form the class autosubmit, this way you get a behavior like an AJAX request. Below is a small snippet of such a ConfigController/Form:

    <?php

    namespace Icinga\Module\Testmodule\Forms\Test;
    use Icinga\Web\Form;
 
    class TestForm extends Form 
    {
      public function init()
      {
        $this->setName('form_test_form');
        $this->setSubmitLabel('Save Changes');
      }

      public function createElements(array $formData)
      {
          // Load cars
          $this->addElement(
              'select',
              'car',
              array(
                  'label' => $this->translate('Car'),
                  'multiOptions' => [
                      '' => '(select option)',
                      'audi' => 'Audi',
                      'vw' => 'VW'
                  ],
                  // 'autosubmit' acts like an AJAX-Request
                  'class' => 'autosubmit'
              )
          );

          // Select model
          if (isset($formData['car']) && $formData['car'] === 'audi') {
              $this->addElement(
                  'select',
                  'model',
                  array(
                      'label' => $this->translate('Model'),
                      'multiOptions' => [
                          '' => '(select model)',
                          'A1',
                          'A6'
                      ],
                      'required' => true,
                  )
              );
          } elseif (isset($formData['car']) && $formData['car'] === 'vw') {
              $this->addElement(
                  'select',
                  'model',
                  array(
                      'label' => $this->translate('Model'),
                      'multiOptions' => [
                          '' => '(select model)',
                          'Golf',
                          'Polo'
                      ],
                      'required' => true,
                  )
              );
          }
      }  
    }

If you now include the view script, you get a form that looks like this:



Thanks to the framework of Icinga Web 2, it is possible to create a module very quickly as needed. If this has whetted your appetite for a bit of programming, I can recommend the training materials already available on Github!

3 Likes