Agregar un elemento de formulario de imagen a un formulario de agregar / editar

12

Estoy construyendo un módulo CRUD para Magento 2 usando componentes ui para la lista y el formulario de administración y una de mis entidades tiene un campo de imagen.
Pero no puedo hacer que funcione como debería.
Así es como debería funcionar.
Cuando está en modo agregar o en modo edición sin imagen cargada, debería verse como una simple entrada de archivo.

Cuando se carga un archivo, debe mostrar la vista previa de la imagen y un cuadro de eliminación debajo de él.

No estoy buscando exactamente este diseño. Podría verse de manera diferente pero tener la misma funcionalidad.

En Magento 1 pude hacer esto, simplemente creando mi propio renderizador de bloques

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;
    }
}

Y agregando esto en mi bloque de formulario

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

Pero no tengo bloque de formulario en Magento 2.
Sé que puedo usar un nombre de clase para un campo de formulario en el archivo de componentes de la interfaz de usuario

    <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>

Obviamente tengo que crear esta clase, pero ¿qué debo extender?
Todo lo que sé es que necesito implementar la interfaz Magento\Framework\View\Element\UiComponentInterfacepero no encontré nada que pueda extender.
Entonces, mi verdadera pregunta es: ¿Puedo extender alguna clase para lograr el comportamiento deseado? Si no, ¿cómo puedo comenzar a crear este renderizador de elementos?

Marius
fuente
Hola, @Marius, intenté usar tu ejemplo para poder agregar imágenes de productos en mi página de edición de cuadrícula personalizada, pero obtuve este error: Error grave: no se encontró la clase 'Varien_Data_Form_Element_' en ... \ lib \ Varien \ Data \ Form \ Abstract.php en línea 146
bestwebdevs

Respuestas:

21

Encontré una manera de hacerlo sin requerir una clase adjunta al campo. Quiero decir que hay una clase adjunta al elemento de formulario pero no como un renderizador.
La columna debe definirse así:

<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>

También necesitaba crear el archivo de plantilla de vista previa al que hace referencia [Namespace]_[Module]/image-preview.
Eso es lo app/code/[Namespace]/[Module]/view/adminhtml/web/template/image-preview.htmlque se ve así:

<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>

Este código generará un campo como este:

Después de cargar una imagen (en tiempo real) se ve así:

El url elemento dentro de uploaderConfiges la url donde se publica la imagen cuando se carga. Entonces necesitaba crear esto también:

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);
    }
}

Esta clase usa una instancia [Namespace]\[Module]\Model\ImageUploadersimilar a \Magento\Catalog\Model\ImageUploader.

Esto parece funcionar. Todavía tengo problemas para guardar la imagen en la base de datos, pero ese es un problema totalmente diferente.
Usé como inspiración el imagecampo para la entidad de categoría

Marius
fuente
Puedo cargar con éxito la imagen y guardar el nombre de la imagen en la base de datos, luego, cuando abro el registro que acabo de crear, todos los campos que no sean el campo de la imagen se muestran como se esperaba. Cuando cambio el campo de imagen a un campo de "texto" normal, se mostrará. ¿Tienes alguna idea sobre esto?
Nero
1
@Nerón. Necesita el valor de la imagen en cierto formato json. Aquí hay un ejemplo sobre cómo puede transformarlo en el json adecuado
Marius
No quiero cargar una imagen, pero quiero imagen de la pantalla en el interfaz de usuario Admin form.Actually puedo subir la imagen de la forma frontend y quiero mostrarlo en la interfaz de usuario de administración form.So ayuda por favor cómo hacerlo
Sneha Panchal
Hay un error en [Espacio de nombres] [Módulo] \ Controlador \ Adminhtml [Entidad] \ Imagen \ upload.php en la línea número 61 Por favor verifique y actualice la respuesta.
Príncipe Patel
@PrincePatel ¿Cuál es el mensaje de error?
Marius
2

Sí, la clase que debes extender es \Magento\Ui\Component\Form\Element\AbstractElement.

Esta clase implementa lo ElementInterfaceque se extiende a lo UiComponentInterfaceque se refiere.

Además de eso, si marca los componentes declarados debajo Magento\Ui\Component\Form\Element, puede ver que todos extienden esa clase.

La razón por la que elegiría esta clase es porque el rendermétodo de \Magento\Backend\Block\Widget\Form\Renderer\Elementsolo acepta dicho tipo de clase:(Esto es realmente una instancia de Magento\Framework\Data\Form\Element\AbstractElementeso es aceptado, no \Magento\Ui\Component\Form\Element\AbstractElement)

Raphael en Digital Pianism
fuente
¿Alguna sugerencia sobre cómo debería ser mi clase?
Marius
@Marius hmmm No estoy muy seguro, intentaré averiguarlo
Raphael en Digital Pianism
1
No creo que necesites hacer eso todavía. Creo que encontré una solución sin usar una clase en el componente ui, pero primero necesito probar.
Marius
@Marius hmmmm Creo que estaba equivocado, creo que deberías revisar eso: github.com/magento/magento2-samples/tree/master/…
Raphael en Digital Pianism