Adicionando um elemento de formulário de imagem a um formulário de adição / edição

12

Estou construindo um módulo CRUD para Magento 2 usando componentes da interface do usuário para a lista e o formulário de administração e uma das minhas entidades possui um campo de imagem.
Mas não posso fazê-lo funcionar como deveria.
Aqui está como deve funcionar.
Quando no modo de adição ou no modo de edição, sem imagem carregada, deve parecer uma simples entrada de arquivo.

Quando um arquivo é carregado, ele deve mostrar a visualização da imagem e uma caixa de exclusão abaixo.

Não estou procurando exatamente esse design. Pode parecer diferente, mas tem a mesma funcionalidade.

No Magento 1 eu pude fazer isso, apenas criando meu próprio renderizador de bloco

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

E adicionando isso no meu bloco de formulário

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

Mas não tenho nenhum bloco de formulário no Magento 2.
Sei que posso usar um nome de classe para um campo de formulário no arquivo de componentes da interface do usuário

    <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 eu tenho que criar essa classe, mas o que devo estender?
Tudo o que sei é que preciso implementar a interface, Magento\Framework\View\Element\UiComponentInterfacemas não encontrei nada que pudesse estender.
Portanto, minha verdadeira pergunta é: Posso estender algumas aulas para alcançar o comportamento desejado? Caso contrário, como posso começar a criar esse elemento renderizador?

Marius
fonte
Oi @Marius, tentei usar seu exemplo para poder adicionar imagens de produtos na minha página de edição de grade personalizada, mas obtive este erro: Erro fatal: A classe 'Varien_Data_Form_Element_' não foi encontrada em ... \ lib \ Varien \ Data \ Form \ Abstract.php na linha 146
bestwebdevs

Respostas:

21

Eu encontrei uma maneira de fazer isso sem exigir uma classe anexada ao campo. Quero dizer, há uma classe anexada ao elemento do formulário, mas não como renderizador.
A coluna deve ser definida como esta:

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

Eu também precisava criar o arquivo de modelo de visualização mencionado por [Namespace]_[Module]/image-preview.
Isso é app/code/[Namespace]/[Module]/view/adminhtml/web/template/image-preview.htmlassim:

<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 irá gerar um campo como este:

Após o upload de uma imagem (em tempo real), fica assim:

O url item dentro do uploaderConfigé o URL em que a imagem é postada quando carregada. Então, eu precisava criar isso também:

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 classe usa uma instância [Namespace]\[Module]\Model\ImageUploadersemelhante a \Magento\Catalog\Model\ImageUploader.

Isso parece funcionar. Ainda tenho problemas para salvar a imagem no banco de dados, mas essa é uma questão totalmente diferente.
Usei como inspiração o imagecampo para a entidade de categoria

Marius
fonte
Posso fazer upload da imagem com sucesso e salvar o nome da imagem no banco de dados; quando abro o registro que acabei de criar, todos os campos que não sejam o campo de imagem são exibidos conforme o esperado. Quando altero o campo da imagem para apenas um campo "texto" normal, ele será exibido. voce tem alguma ideia sobre isso?
Nero
1
@Nero. Você precisa do valor da imagem em um determinado formato json. Aqui está um exemplo de como você pode transformá-lo no json apropriado
Marius
Eu não quero fazer o upload de imagem, mas eu quero imagem do monitor para a administração Ui form.Actually i upload de imagem de forma frontend e quiser exibi-lo na administração ui form.So Por favor, ajude-me como fazer
Sneha Panchal
Há um erro em [Namespace] [Module] \ Controller \ Adminhtml [Entity] \ Image \ upload.php no número da linha 61 Verifique e atualize a resposta.
Prince Patel
@PrincePatel Qual é a mensagem de erro?
Marius
2

Sim, a classe que você deve estender é \Magento\Ui\Component\Form\Element\AbstractElement.

Esta classe implementa o ElementInterfaceque em si estende o que UiComponentInterfacevocê está se referindo.

Além disso, se você verificar os componentes declarados abaixo, Magento\Ui\Component\Form\Elementpoderá ver que todos eles estendem essa classe.

A razão pela qual eu escolheria essa classe é porque o rendermétodo \Magento\Backend\Block\Widget\Form\Renderer\Elementaceita apenas esse tipo de classe:(Esta é realmente uma instância Magento\Framework\Data\Form\Element\AbstractElementque é aceita, não \Magento\Ui\Component\Form\Element\AbstractElement)

Raphael na Digital Pianism
fonte
Alguma dica sobre como deve ser minha turma?
Marius
@Marius hmmm eu não estou muito certo, eu vou tentar descobrir
Raphael em Digital pianismo
1
Eu não acho que você precise fazer isso ainda. Acho que encontrei uma solução sem usar uma classe no componente da interface do usuário, mas preciso testar primeiro.
Marius
@Marius hmmmm Acho que estava errado, acho que você deveria conferir: github.com/magento/magento2-samples/tree/master/…
Raphael no Digital Pianism