Zend Framework 3 - 使用 javascript 添加和删除新的输入元素部分

Zend Framework 3 - Add and Remove new input element section using javascript

我想在单击锚标记或按钮时以 zend 形式添加多个学校位置。 这样 zend 表单验证就可以应用于所有动态创建的字段 请参阅附件 image.I 想要克隆 div 并在图像中使用红色边框

下面是SchoolControllerClass

<?php



namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use School\Service\SchoolManager;
use Doctrine\ORM\EntityManager;
use Zend\View\Model\ViewModel;
use Application\Form\AddSchoolForm;
use School\Entity\School;
use School\Entity\SchoolLocation;

class SchoolController extends AbstractActionController {

    /**
     * Entity manager.
     * @var Doctrine\ORM\EntityManager
     */
    private $entityManager;

    /**
     * School manager.
     * @var School\Service\SchoolManager 
     */
    private $schoolManager;

    public function __construct($entityManager, $schoolManager) {
        $this->entityManager = $entityManager;
        $this->schoolManager = $schoolManager;
    }

    public function addAction() {
        $form = new AddSchoolForm();


        // Check if user has submitted the form
        if ($this->getRequest()->isPost()) {

            // Fill in the form with POST data
            $data = $this->params()->fromPost();
            $form->setData($data);
            // Validate form
            if ($form->isValid()) {
                $reqData = array(
                    'name' => $data['name'],
                    'description' => $data['description'],
                    'active' => 1,
                    'school_location' => (object) array(
                        (object) array(
                            "apartment_number" => $data['apartment_number'],
                            "street_name" => $data['street_name'],
                            "city" => $data['city'],
                            "state" => $data['state'],
                            "pin" => $data['pin'],
                            "active" => 1)
                    )
                );

                $this->schoolManager->addSchool((object) $reqData);
            } else {
                print_r($form->getMessages());
                die("not valid data");
                $isLoginError = true;
            }
        }
        return new ViewModel([
            'form' => $form
        ]);
    }
}

下面是AddSchoolForm Class:

<?php

namespace Application\Form;

use Zend\Form\Element;
use Zend\Form\Form;
use Zend\InputFilter\InputFilter;

/**
 * This form is used to collect user's login, password and 'Remember Me' flag.
 */
class AddSchoolForm extends Form {

    /**
     * Constructor.
     */
    public function __construct() {
        // Define form name
        parent::__construct('addschool-form');

        // Set POST method for this form
        $this->setAttribute('method', 'post');

        $this->addElements();
        $this->addInputFilter();
    }

    /**
     * This method adds elements to form (input fields and submit button).
     */
    protected function addElements() {

        $this->add([
            'attributes' => array(
                'name' => 'name',
                'type' => 'text',
                'id' => 'name',
                'class' => 'form-control',
                'required' => 'required',
            ),
            'options' => [
                'label' => 'School Name',
            ],
        ]);

        // Add "desc" field
        $this->add([
            'attributes' => array(
                'name' => 'description',
                'type' => 'text',
                'id' => 'description',
                'class' => 'form-control',
                'required' => 'required',
            ),
            'options' => [
                'label' => 'Description',
            ],
        ]);


        $this->add([
            'type' => 'hidden',
            'name' => 'active',
            'value' => 1
        ]);

        // Add "school location" field
        $this->add([
            'attributes' => array(
                'name' => 'apartment_number',
                'type' => 'text',
                'id' => 'apartment_number',
                'class' => 'form-control'
            ),
            'options' => [
                'label' => 'Apartment Number',
            ],
        ]);


        $this->add([
            'attributes' => array(
                'name' => 'street_name',
                'type' => 'text',
                'id' => 'street_name',
                'class' => 'form-control'
            ),
            'options' => [
                'label' => 'Street Name',
            ],
        ]);



        $this->add([
            'attributes' => array(
                'name' => 'city',
                'type' => 'text',
                'id' => 'city',
                'class' => 'form-control'
            ),
            'options' => [
                'label' => 'City',
            ],
        ]);



        $this->add([
            'attributes' => array(
                'name' => 'state',
                'type' => 'text',
                'id' => 'state',
                'class' => 'form-control'
            ),
            'options' => [
                'label' => 'State',
            ],
        ]);


        $this->add([
            'attributes' => array(
                'name' => 'pin',
                'type' => 'text',
                'id' => 'pin',
                'class' => 'form-control'
            ),
            'options' => [
                'label' => 'PIN',
            ],
        ]);



        // Add the Submit button
        $this->add([
            'type' => 'submit',
            'name' => 'submit',
            'attributes' => [
                'value' => 'Sign in',
                'id' => 'submit',
            ],
        ]);
    }

    /**
     * This method creates input filter (used for form filtering/validation).
     */
    private function addInputFilter() {
        // Create main input filter
        $inputFilter = new InputFilter();
        $this->setInputFilter($inputFilter);

        // Add input for "email" field
        $inputFilter->add([
            'name' => 'name',
            'required' => true,
            'filters' => [
                ['name' => 'StringTrim'],
            ],
            'validators' => [
                [
                    'name' => 'StringLength',
                    'options' => [
                        'min' => 5,
                        'max' => 20
                    ],
                ],
            ],
        ]);


        $inputFilter->add([
            'name' => 'description',
            'required' => true,
            'filters' => [
            ],
            'validators' => [
                [
                    'name' => 'StringLength',
                    'options' => [
                        'min' => 5,
                        'max' => 64
                    ],
                ],
            ],
        ]);
    }

}

下面是查看文件add.phtml

<script type="text/javascript">
    function addSchoolLocation(){
        $( ".schoolLocation" ).clone().appendTo( ".schoolLocation" );
    }


    </script>
<!-- Content Header (Page header) -->
<section class="content-header">
    <ol class="breadcrumb">
        <li><a href="#"><i class="fa fa-dashboard"></i> Home</a></li>
        <li class="active">Add School</li>
    </ol>
</section>

<!-- Main content -->
<section class="content">
    <div class="row">
        <!-- left column -->
        <div class="col-md-12">
            <!-- general form elements -->
            <div class="box box-primary form-custome">
                <div class="box-header with-border">
                    <h3 class="box-title">Add School <ul class="add-icon-new">
                            <li><a href="#" class="i-down"><i class="fa fa-angle-down"></i></a></li>
                            <li><a href="#" class="i-refresh"><i class="fa fa-refresh" aria-hidden="true"></i>
                                </a></li>
                            <li><a href="#" class="i-close"><i class="fa fa-times" aria-hidden="true"></i></a></li>
                        </ul>
                    </h3>
                </div>
                <h5 class="form-heading">School Information</h5>
                <form role="form" method="post">
                    <div class="box-body">

                        <div class="form-group col-md-3 col-sm-6">
                            <?= $this->formLabel($form->get('name')); ?>
                            <?= $this->formElement($form->get('name')); ?>
                        </div>

                        <div class="form-group col-md-3 col-sm-6">
                            <?= $this->formLabel($form->get('description')); ?>
                            <?= $this->formElement($form->get('description')); ?>
                        </div>

                        <?= $this->formElement($form->get('active')); ?>         
                        <h5 class="form-heading">School Location</h5>
                        <div class="schoolLocation">
                            <div class="form-group col-md-3 col-sm-6">
                                <?= $this->formLabel($form->get('apartment_number')); ?>
                                <?= $this->formElement($form->get('apartment_number')); ?>
                            </div>
                            <div class="form-group col-md-3 col-sm-6">
                                <?= $this->formLabel($form->get('street_name')); ?>
                                <?= $this->formElement($form->get('street_name')); ?>
                            </div>
                            <div class="form-group col-md-3 col-sm-6">
                                <?= $this->formLabel($form->get('city')); ?>
                                <?= $this->formElement($form->get('city')); ?>
                            </div>
                            <div class="form-group col-md-3 col-sm-6">
                                <?= $this->formLabel($form->get('state')); ?>
                                <?= $this->formElement($form->get('state')); ?>
                            </div>
                            <div class="form-group col-md-3 col-sm-6">
                                <?= $this->formLabel($form->get('pin')); ?>
                                <?= $this->formElement($form->get('pin')); ?>
                            </div>
                        </div>
                        <div>
                            <a href="javascript:void(0);" onclick="addSchoolLocation();">Add School Location</a>
                            <a href="javascript:void(0);" id="addElement">Add School Location</a>
                        </div>

                        <div class=" form-group col-sm-12">

                            <button class="save">Save</button>
                            <button class="reset">Reset</button>
                        </div>
                    </div>
                </form>
            </div>

        </div>
    </div>
    <!-- /.row -->
</section>
<!-- /.content -->

我想用 class schoollocation

克隆 div

注意*: 我尝试了以下解决方案,但对我没有任何效果,因为这些不是 Zend Framework-3 的解决方案

  1. Zend Framework - Add new input element using javascript

  2. https://docs.zendframework.com/zend-form/collections/#form-collections

您要查找的是 Collections (which you linked) and Fieldsets 的用法。

您使用 Fieldset 来表示实体。在此示例中,Fieldset 是 Location,附加到 School.

此外,School 作为与 LocationOne To Many 关系。

因此,您将有一个 SchoolFieldset class,它需要一个 Collection Element

下面是一个非常简化的设置示例。

后端

位置字段集

class LocationFieldset
{
    public function init()
    {
        parent::init();

        $this->add([
            'name' => 'name',
            'required' => true,
            'type' => Text::class,
            'options' => [
                'label' => _('Name'),
            ],
        ]);

        // ... Add whatever for Location
    }
}

学校田野集

class SchoolFieldset
{
    /**
     * @var LocationFieldset
     */
    protected $locationFieldset;

    public function __construct(LocationFieldset $locationFieldset) 
    {
        $this->locationFieldset($locationFieldset);
    }

    public function init()
    {
        parent::init();

        $this->add([
            'name' => 'name',
            'required' => true,
            'type' => Text::class,
            'options' => [
                'label' => _('Name'),
            ],
        ]);

        $this->add([
            'type' => Collection::class,
            'required' => true,
            'name' => 'locations',
            'options' => [
                'label' => _('Locations'),
                'count' => 1,                     // Initial amount of Fieldsets on-load
                'allow_add' => true,              // Allows creation of 0/multiple
                'allow_remove' => true,           // Allows removal
                'should_create_template' => true, // Creates template in the HTML in a <span data-template="the whole html here"></span> -> JavaScript this bit for duplication/removal
                'target_element' => $this->locationFieldset, // A pre-loaded Fieldset must be passed here, not just the FQCN as you would for including a Fieldset not in a Collection
            ],
        ]);

        // ... Add whatever
    }
}

学校形式

class SchoolForm extends CustomAbstractForm
{
    public function init()
    {
        $this->add([
            'name' => 'school',
            'type' => SchoolFieldset::class,
            'options' => [
                'use_as_base_fieldset' => true,
            ],
        ]);

        //Call parent initializer. (Default for me it adds a submit button)
        parent::init();
    }
}

Front-end

在表格的视图中,我加载了一点JavaScript。它基于 Zend Framework 文档中提供的演示数据。

请注意,这些文档不考虑删除(因此,如果您有 HTML objects 且 ID 为 0-1-2,并且您删除了 1,它将被计算在内,来到 2 并创建另一个 2,给你 0-2-2,从而覆盖你已经拥有的第二个。

我目前在一个项目中的JavaScript是这样的(抱歉,不能给你所有的,但这应该让你开始):

按钮

var $addButton = $('<button type="button" data-action="add-fieldset" class="btn btn-primary">Add another</button>');
var $removeButton = $('<button type="button" data-action="remove-fieldset" class="btn btn-danger">Remove</button>');

用法

$('body').on('click', 'button[type="button"][data-action="add-fieldset"]', function () {
    addCollectionFieldset(this);
});

$('body').on('click', 'button[type="button"][data-action="remove-fieldset"]', function () {
    removeCollectionFieldset(this);
});

function addCollectionFieldset(element) {
    var $element = $(element);
    var $fieldsetDataSpan = $element.siblings('span[data-name="fieldset-data"]');
    var fieldsetCount = $fieldsetDataSpan.data('fieldset-count');

    var escapedTemplate = $element.siblings('span[data-template]').data('template');
    var $replaced = $(escapedTemplate.replace(/__index__/g, fieldsetCount));
    $replaced.append($removeButton.clone());

    $($replaced).insertAfter($element.siblings('fieldset:last'));
    $('<hr>').insertBefore($element.siblings('fieldset:last'));

    $fieldsetDataSpan.data('fieldset-count', fieldsetCount + 1); // Up the count by one fieldset
}

function removeCollectionFieldset(element) {
    $(element).parent().remove();
}

注意: "Remove" 按钮位于 Collection 中的每个字段集中。 "Add another" 按钮位于 Collection 下方。

如何解决这个问题,由您决定。

查看

<?= $this->form($form) ?>
<?php $this->inlineScript()->prependFile($this->basePath('js/form.js')) ?>

控制器动作

public function addAction()
{
    /** @var SchoolForm $form */
    $form = $this->getSchoolForm();

    /** @var Request $request */
    $request = $this->getRequest();
    if ($request->isPost()) {
        $form->setData($request->getPost());

        if ($form->isValid()) {
            /** @var School $school */
            $school = $form->getObject();

            $this->getObjectManager()->persist($school);

            try {
                $this->getObjectManager()->flush();
            } catch (Exception $e) {

                throw new Exception(
                    'Could not save. Error was thrown, details: ' . $e->getMessage(),
                    $e->getCode(),
                    $e->getPrevious()
                );
            }

            return $this->redirectToRoute('schools/view', ['id' => $school->getId()]);
        }
    }

    return [
        'form' => $form,
        'validationMessages' => $form->getMessages() ?: '',
    ];
}

控制器工厂

class AddControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        /** @var ObjectManager $objectManager */
        $objectManager = $container->get(EntityManager::class);

        /** @var FormElementManagerV3Polyfill $formElementManager */
        $formElementManager = $container->get('FormElementManager');
        /** @var SchoolForm $schoolForm */
        $schoolForm = $formElementManager->get(SchoolForm::class);

        return new AddController($objectManager, $schoolForm);
    }
}

FormFactory

class SchoolFormFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $objectManager = $container->get(EntityManager::class);
        $translator = $container->get('MvcTranslator');
        $inputFilterPluginManager = $container->get('InputFilterManager');

        $inputFilter = $inputFilterPluginManager->get(SchoolFormInputFilter::class); // Did not show this one

        /** @var SchoolForm $form */
        $form = new SchoolForm();
        $form->setObjectManager($objectManager);
        $form->setTranslator($translator);
        $form->setInputFilter($inputFilter);

        return $form;
    }
}

FormFactory

class SchoolFieldsetFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {        
        $objectManager = $container->get(EntityManager::class);
        $translator = $container->get('MvcTranslator');

        $fieldset = new SchoolFieldset();
        $fieldsetObject = new School();

        /** @var SchoolFieldset $fieldset */
        $fieldset = new $fieldset($objectManager(), 'school');
        $fieldset->setHydrator(
            new DoctrineObject($objectManager())
        );
        $fieldset->setObject($fieldsetObject);
        $fieldset->setTranslator($translator);

        return $fieldset;
    }
}

如果您有空闲时间,我建议您查看我创建的存储库中的更多示例,以帮助在 ZF 和 ZF with Doctrine 中快速创建表单。带有示例的自述文件 is here