HowTo: Add an extra Form Field to another modules Form

  • Overview

    You want to add an extra Field to another modules Form. You want to do it so that it shows when your module is active.

    An example of this that currently is easy to see is the "Add to Timeline" checkbox that appears on modules CREATE and UPDATE forms for things like Videos and Audio files.

    The CREATE and UPDATE forms for the Video Create are provided by the jrVideo module but they contain an "Add to Timeline" checkbox that was put there by the jrAction module.

    Its how to do this that we are looking at here.
  • screenshot of the "Add to Timeline" on the CREATE form for an audio item
  • All of the other fields on that form were put there by the _create() function in that modules index.php file.

    So for the audio file create form, the controlling function is view_jrAudio_create() found in /modules/jrAudio/index.php

    Only the "Add to Timeline" was created by Events and Listeners from another module.
  • The Audio modules create form

    If you look inside the view_jrAudio_create() function you will see this kind of structure for each of the form fields.
    .......
        // Audio Title
    
        $_tmp = array(
            'name'      => 'audio_title',
            'label'     => 10,
            'help'      => 11,
            'type'      => 'text',
            'validate'  => 'printable',
            'required'  => true
        );
        jrCore_form_field_create($_tmp);
    
        // Audio Genre
    
        $_tmp = array(
            'name'      => 'audio_genre',
            'label'     => 12,
            'help'      => 13,
            'type'      => 'select_and_text',
            'validate'  => 'printable',
            'required'  => true
        );
        jrCore_form_field_create($_tmp);
    
        // Audio Album
    
        $_tmp = array(
            'name'      => 'audio_album',
            'label'     => 31,
            'help'      => 32,
            'type'      => 'select_and_text',
            'validate'  => 'printable',
            'required'  => false
        );
        jrCore_form_field_create($_tmp);
    .........
  • Each of the sets outline how a form field should be set up.

    The numbers correspond to the entries in the modules language file found at:
    /modules/jrAudio/lang/en-US.php

    So in the above section you see
    'help' => 13 
    That will be replaced by the $language string. If you didn't want your module to use the language system, you could put the text you want to display for the form label directly into the $_tmp array.
    'help' => "If you have already entered genres in other audio files, you may select any previous genre, or enter a new genre in text field" 
    Otherwise the language file is used.
    $lang[11] = 'Enter a title for the audio file - this will be shown your profile.';
    $lang[12] = 'genre';
    $lang[13] = 'If you have already entered genres in other audio files, you may select any previous genre, or enter a new genre in text field';
    $lang[14] = 'audio file';
    $lang[15] = 'select and upload the audio file.';
    $lang[16] = 'cover image';
    $lang[17] = 'if you would like to associate an image file with this audio file, upload it here. If you do not select a cover image and there is an embedded image in the MP3 file(s), it will be used.';
    $lang[18] = 'An error was encountered creating the audio file - please try again.';
  • Using Events and Listeners to inject an additional Form Field

    The goal is to have an additional Form Field added to any other modules forms. ( Or target specific forms if that is the preferred use-case ).

    In any case first we need a module.

    HINT: If you don't want to do this by building a module, its very easy to do using the Form Designer.

    Docs: "Using the Form Designer"
    but in this case we do want to do it programmatically, so we need a module.
  • The Events and Listeners page goes into more detail about what these are, so for here I'll just paste the basic include.php file that we need for the start of our module.
    The event we want to listen for is the 'form_display' event, so we register that in our modules _init() function along with the function that will fire when that event is triggered.

    For the sake of this doc, the modules name is xxFoo

    <?php
    /**
     * @copyright
     */
    
    // make sure we are not being called directly
    
    defined('APP_DIR') or exit();
    
    /**
     * meta
     */
    function xxFoo_meta()
    {
        $_tmp = array(
            'name'        => 'Foo',
            'url'         => 'foo',
            'version'     => '1.0.0',
            'developer'   => 'Some guy, &copy;' . strftime('%Y'),
            'description' => 'Used to add a form field to the profile settings module',
            'category'    => 'custom',
            'license'     => 'mpl'
        );
        return $_tmp;
    }
    
    /**
     * init
     */
    function xxFoo_init()
    {
    
        // extra profile settings option
    
        jrCore_register_event_listener('jrCore', 'form_display', 'xxFoo_form_display_listener');
    
        return true;
    }
    
    //----------------------
    
    // EVENT LISTENERS
    
    //----------------------
    
    
    /**
     * Save an extra field on the Profile Settings form
     * @param $_data array Array of information from trigger
     * @param $_user array Current user
     * @param $_conf array Global Config
     * @param $_args array additional parameters passed in by trigger caller
     * @param $event string Triggered Event name
     * @return array
     */
    function xxFoo_form_display_listener($_data, $_user, $_conf, $_args, $event)
    {
    
        if (isset($_data['form_view']) && $_data['form_view'] == 'jrProfile/settings') {
            // Profile Color
    
            $_tmp = array(
                'name'      => 'profile_color',
                'label'     => "Profile Color",
                'help'      => "Add a hex code color to change the background of your profile",
                'type'      => 'text',
                'required'  => false,
                'validate'  => 'printable'
            );
            jrCore_form_field_create($_tmp);
        }
        return $_data;
    }
    
  • So what we have there is enough to add a "Profile Color" form field to the profile settings form.

    If the module is active the field will show.
  • screenshot of the "Profile Color" form field added to the profile settings form.
  • How we got the correct variables

    When adding a listener function to your include.php file of your module, the same variables always come in ($_data, $_user, $_conf, $_args, $event)

    Along with the event firing you get that data to use to manipulate whatever is going on. Always remember to finish your function by returning $_data even if you have altered it.

    So before the form is being displayed its passed around all the other modules to see if they want to alter it, we do.

    We make our change to the form and pass it back.

    What we want to be careful of is not to add our "profile_color" field to ALL forms because not all forms are going into the datastore with the 'profile_' prefix, so our created form field would fail on those.

    So we add a check on the $_data array to make sure we only target the 'jrProfile/settings' form.

    The way we find out that this is the name for the form we're after is to put a breakpoint on the
    return $_data;
    and see what is contained in the variables we receive when we open the form we are interested in in a browser.

    So in a browser open a profile settings form:
    http://site.com/profile/settings/profile_id=1/id=1

    and you will see what the variables have in your debugger.
  • screenshot of the $_data values in the debugger of phpstorm
  • We can see that the $_data['form_view'] seams very specific to the module and view that we are on, and indeed it is. Use that to determine which form you are targeting.

    The saved info will go into the datastore along with the rest of the form and you can use {jrCore_list} to recall it the same as any other datastore item.

Tags