12

I'm building a CRUD module for Magento 2 using ui components for admin list and form and one of my entities has an image field.
But I cannot make it work as it should.
Here is how it should work.
When in add mode or in edit mode with no uploaded image it should look like a simple file input.

When a file is uploaded it should show the image preview and a delete box below it.

I'm not looking for the exactly this design. It could look differently but have the same functionality.

In Magento 1 I was able to do this, just by creating my own block renderer

class {{Namespace}}_{{Module}}_Block_Adminhtml_{{Entity}}_Helper_Image extends Varien_Data_Form_Element_Image
{
    protected function _getUrl()
    {
        $url = false;
        if ($this->getValue()) {
            $url = Mage::helper('{{namespace}}_{{module}}/{{entity}}_image')->getImageBaseUrl().$this->getValue();
        }
        return $url;
    }
}

And adding this in my form block

    $fieldset->addType(
        'image',
        Mage::getConfig()->getBlockClassName('{{namespace}}_{{module}}/adminhtml_{{entity}}_helper_image')
    );

But I have no form block in Magento 2.
I know I can use a class name for a form field in the ui components file

    <field name="image" class="Class\Name\Here">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="dataType" xsi:type="string">text</item>
                <item name="label" xsi:type="string" translate="true">Resume</item>
                <item name="formElement" xsi:type="string">image</item>
                <item name="source" xsi:type="string">[entity]</item>
                <item name="dataScope" xsi:type="string">image</item>
            </item>
        </argument>
    </field>

Obviously I have to create this class, but what should I extend?
All I know is that I need to implement the interface Magento\Framework\View\Element\UiComponentInterface but I found nothing I can extend.
So my real question is: Can I extend some class to achieve the desired behavior? If not, how can I start creating this element renderer?

  • Hi @Marius , I tried to use your example to be able to add product images in my custom grid edit page, but got this error : Fatal error: Class 'Varien_Data_Form_Element_' not found in ...\lib\Varien\Data\Form\Abstract.php on line 146 – bestwebdevs May 25 '17 at 18:14
2

Yes, the class you should extend is \Magento\Ui\Component\Form\Element\AbstractElement.

This class implements the ElementInterface which itself extends the UiComponentInterface you're referring to.

On top of that, if you check the components declared under Magento\Ui\Component\Form\Element you can see that they all extend that class.

The reason I would choose this class is because the render method of \Magento\Backend\Block\Widget\Form\Renderer\Element only accepts such class type: (This is actually an instance of Magento\Framework\Data\Form\Element\AbstractElement that is accepted, not \Magento\Ui\Component\Form\Element\AbstractElement )

21

I found a way to do it without requiring a class attached to the field. I mean there is a class attached to the form element but not as a renderer.
The column should be defined as this:

<field name="image">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="dataType" xsi:type="string">string</item>
            <item name="source" xsi:type="string">[entity]</item>
            <item name="label" xsi:type="string" translate="true">Image</item>
            <item name="visible" xsi:type="boolean">true</item>
            <item name="formElement" xsi:type="string">fileUploader</item>
            <item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
            <item name="previewTmpl" xsi:type="string">[Namespace]_[Module]/image-preview</item>
            <item name="required" xsi:type="boolean">false</item>
            <item name="uploaderConfig" xsi:type="array">
                <item name="url" xsi:type="url" path="[namespace_module]/[entity]_image/upload"/>
            </item>
        </item>
    </argument>
</field>

I also needed to create the preview template file referenced by [Namespace]_[Module]/image-preview.
That is app/code/[Namespace]/[Module]/view/adminhtml/web/template/image-preview.html that looks like this:

<div class="file-uploader-summary">
    <div class="file-uploader-preview">
        <a attr="href: $parent.getFilePreview($file)" target="_blank">
            <img
                class="preview-image"
                tabindex="0"
                event="load: $parent.onPreviewLoad.bind($parent)"
                attr="
                    src: $parent.getFilePreview($file),
                    alt: $file.name">
        </a>

        <div class="actions">
            <button
                type="button"
                class="action-remove"
                data-role="delete-button"
                attr="title: $t('Delete image')"
                click="$parent.removeFile.bind($parent, $file)">
                <span translate="'Delete image'"/>
            </button>
        </div>
    </div>

    <div class="file-uploader-filename" text="$file.name"/>
    <div class="file-uploader-meta">
        <text args="$file.previewWidth"/>x<text args="$file.previewHeight"/>
    </div>
</div>

This code will generate a field like this:

After uploading an image (real time) it looks like this:

The url item inside the uploaderConfig is the url where the image is posted when uploaded. So I needed to create this also:

namespace [Namespace]\[Module]\Controller\Adminhtml\[Entity]\Image;

use Magento\Framework\Controller\ResultFactory;

/**
 * Class Upload
 */
class Upload extends \Magento\Backend\App\Action
{
    /**
     * Image uploader
     *
     * @var \[Namespace]\[Module]\Model\ImageUploader
     */
    protected $imageUploader;

    /**
     * @param \Magento\Backend\App\Action\Context $context
     * @param \[Namespace]\[Module]\Model\ImageUploader $imageUploader
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \[Namespace]\[Module]\Model\ImageUploader $imageUploader
    ) {
        parent::__construct($context);
        $this->imageUploader = $imageUploader;
    }

    /**
     * Check admin permissions for this controller
     *
     * @return boolean
     */
    protected function _isAllowed()
    {
        return $this->_authorization->isAllowed('[Namespace]_[Module]::[entity]');
    }

    /**
     * Upload file controller action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        try {
            $result = $this->imageUploader->saveFileToTmpDir('image');

            $result['cookie'] = [
                'name' => $this->_getSession()->getName(),
                'value' => $this->_getSession()->getSessionId(),
                'lifetime' => $this->_getSession()->getCookieLifetime(),
                'path' => $this->_getSession()->getCookiePath(),
                'domain' => $this->_getSession()->getCookieDomain(),
            ];
        } catch (\Exception $e) {
            $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
        }
        return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
    }
}

This class uses an instance of [Namespace]\[Module]\Model\ImageUploader that is similar to \Magento\Catalog\Model\ImageUploader.

This seams to work. I still have troubles saving the image in the db but that's a totally different issue.
I used as inspiration the image field for the category entity

  • I can successfully upload image and save image name into database, then when I open record i just created, all fields other than image field are all showing as expected. When I change the image field to just a normal "text" field, then it will show. Do you have any idea about this? – Nero Oct 19 '16 at 14:50
  • 1
    @Nero. You need the image value in a certain json format. Here is an example on how you can transform it to the proper json – Marius Oct 19 '16 at 14:57
  • I don't want to upload image but i want to display image in admin Ui form.Actually i upload image from frontend form and want to display it in admin ui form.So please help me how to do – Sneha Panchal Jan 19 '17 at 7:08
  • There is error in [Namespace][Module]\Controller\Adminhtml[Entity]\Image\upload.php on line number 61 Please check and update answer. – Prince Patel May 26 '17 at 5:47
  • @PrincePatel What's the error message? – Marius May 26 '17 at 6:23

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.