Magento : Dynamic comment loading for admin system config field (Part 2/2)

May 14th, 2014 by in Backend, Development, Magento 2
Magento : Dynamic comment loading for admin system config field (Part 2/2)

In the first part of this tutorial we have seen how a custom model that will render a comment for system configuration field can be defined. We have used this to render a comment depending on saved value of the field. That’s all nice, but what about changing the contents of the comment in real-time without having to save the configuration in order to preview the changes? In this post I will show you how to do exactly that.

 

If you are wondering how can this be useful, there is at least one situation in every default Magento that could benefit from this. If you have ever used PayPal’s Express checkout in Magento, you know that you can select different types of buttons to be displayed on frontend right from payment module’s configuration page. Here’s the catch – you can not preview the design button directly in admin. Instead, you pick a selection, save configuration and go to frontend to see how the button actually looks. I’d say that’s not a very good user experience, so we will cover here something similar: a dropdown system configuration element with image preview. And we will do it by using Magento’s native PrototypeJS.

 

The code

We will start by adding a field in system.xml file of our module. I will call it dynamiccomment for demonstration purposes:

                        <dynamiccomment translate="label">
                            <label>Dynamic Comment</label>
                            <frontend_type>select</frontend_type>
                            <source_model>modulename/adminhtml_system_config_source_dynamiccomment</source_model>
                            <comment>
                                <model>modulename/adminhtml_system_config_source_dynamiccomment_comment</model>
                            </comment>
                            <sort_order>2</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </dynamiccomment>

I will not type the whole system.xml file here, so let’s just assume that our dynamiccomment field belongs to testsection section and testgroup group. If you have ever created your own module with a system.xml file, you probably know that Magento stores fields in groups and groups in sections.

 

Anyway, I have used a custom source model for our field just to get a bit past the default yesno field. So let’s define the source model:

/* File location: Namespace\Modulename\Model\Adminhtml\System\Config\Source\Dynamiccomment.php */
<?php

class Namespace_Modulename_Model_Adminhtml_System_Config_Source_Dynamiccomment
{
    public function toOptionArray()
    {
        return array(
            array('value' => 'empty', 'label' => ' '),
            array('value' => 'red', 'label' => Mage::helper('modulename')->__('Red')),
            array('value' => 'green', 'label' => Mage::helper('modulename')->__('Green')),
        );
    }

    public function toArray()
    {
        return array(
            'empty' => ' ',
            'red'   => Mage::helper('modulename')->__('Red'),
            'green' => Mage::helper('modulename')->__('Green'),
        );
    }
}

We have simply created a dropdown with three options: empty, red and green.

 

Now comes the juicy part – the comment model:

/* File location: Namespace\Modulename\Model\Adminhtml\System\Config\Source\Dynamiccomment\Comment.php */
<?php

class Namespace_Modulename_Model_Adminhtml_System_Config_Source_Dynamiccomment_Comment extends Mage_Core_Model_Config_Data
{
    public function getCommentText(Mage_Core_Model_Config_Element $element, $currentValue)
    {
        $skinUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN);
        $result = "<p id='dynamic_comment'><br />";
        $result .= "<img id='dynamic_comment_image'></p>";
        $result .= "<script type='text/javascript'>
            function render_image()
            {
                var image = $('dynamic_comment_image');
                var field_value = $('testsection_testgroup_dynamiccomment').getValue();
                var image_dir = 'frontend/default/default/images/modulename/';
                var comment = $('dynamic_comment');
                    switch (field_value)
                    {
                        case 'empty':
                            comment.setStyle({display: 'none'});
                            break;
                        case 'red':
                            comment.setStyle({display: 'block'});
                            image.src = '" . $skinUrl . "' + image_dir + 'red.jpg';
                            break;
                        case 'green':
                            comment.setStyle({display: 'block'});
                            image.src = '" . $skinUrl . "' + image_dir + 'green.jpg';
                            break;
                    }
            }

            function init_comment()
            {
                render_image();
                $('testsection_testgroup_dynamiccomment').observe('change', function(){
                    render_image();
                });
            }
            document.observe('dom:loaded', function(){init_comment();});
            </script>";

        return $result;
    }
}

The general idea here is, if the contents of the $result is being passed to be directly rendered by the _prepareFieldComment method from Part 1 of this tutorial, what’s stopping us from passing HTML? Or JavaScript for that matter? Well, nothing really. Whatever is in the $result will be parsed directly where the comment should be rendered.

 

We have started the above code with creating a wrapper paragraph element with our image inside it. I’ve also added a bit of space between our field and the image with a line break. Nothing fancy, really. But before we proceed to JavaScript part, you might ask – how do we know the id of our field? The answer is easy: Magento forms the id of each form element on system configuration page like this: section_group_field, so in our example that would be testsection_testgroup_dynamiccomment.

 

For the JavaScript part:

  • We are calling init_comment() function when the page is loaded (with document.observe);
  • init_comment() function calls render_image() function in order to render the preview image when the page is first loaded;
  • We also call the render_image() function whenever the selection of our dropdown field changes (with $(‘testsection_testgroup_dynamiccomment’).observe);
  • render_image() function loads a different image depending on the value of our field, or hides the wrapping HTML paragraph element if the value is empty;

 

Now you just have to create red.jpg and green.jpg images and place them in skin/frontend/default/default/images/modulename/ folder and you will get something like this:

Red

… or this:

Green

depending on what you select in the dropdown.

 

Summary

  • Magento supports defining custom models for rendering comments depending on the value of your system configuration field;
  • You can access the element itself and all XML tags that define it;
  • You can return pretty much anything with your getCommentText method, including HTML and JavaScript.

 

You can download a sample module that covers both parts of this tutorial here. Oh… and you should probably consider using a Magento block and placing the above HTML and JavaScript in a template (.phtml) file and then grabbing the contents of it in your getCommentText method instead of typing everything directly in $result variable. I just didn’t do in order to avoid complicating this tutorial further. Have fun!

Written by Nikola Stojiljkovic

Nikola is a Certified Magento Backend Developer with a passion for high quality code that follows standards and best practices. He also leads our Magento development teams so you can expect excellent Magento articles from him.


See all articles from this author »

Comment (2)

Posted on June 4, 2014 by axel

Hi, verry interesting. . I would like to use your tip for order comments in back end : having a library of prestored comment could be a gain of time. But i'm not a good coder. How could i subsitue a TXT file to image.src = '" . $skinUrl . "' + image_dir + 'red.jpg'; Thanks

Posted on June 12, 2014 by Nikola Stojiljkovic

If you want to load comments from a file depending on the option that was selected, you just have to open the file at the beginning of getCommentText function and add the lines of the file into an array. I recommend using a CSV file where the first value of each row is an identifier that you can use in your switch statement (in the code above) and the second value is an actual comment message that you want to display. Take a look at fgetcsv and related functions for more info.

 

Regarding the order comments, could you, please, clarify where exactly these comments should appear? In one of the System > Configuration pages or on the actual order management page? If it's the order management page, that's a whole different story :)