首页 文章

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

提问于
浏览
3

我想在点击锚标签或按钮时以zend-form添加多个学校位置 . 因此zend表单验证可以应用于所有动态创建的字段请参阅附图 . 我想在图像中用红色边框克隆div
enter image description here

下面是SchoolController类

<?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类:

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

Note:* 我尝试了下面的解决方案,但没有任何对我有用,因为那些不是Zend Framework-3的解决方案

1 回答

  • 2

    您正在寻找的是Collections(您链接的)和Fieldsets的用法 .

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

    此外, SchoolLocationOne To Many 关系 .

    因此,您将拥有 SchoolFieldset 类,需要Collection Element .

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

    后端

    LocationFieldset

    class LocationFieldset
    {
        public function init()
        {
            parent::init();
    
            $this->add([
                'name' => 'name',
                'required' => true,
                'type' => Text::class,
                'options' => [
                    'label' => _('Name'),
                ],
            ]);
    
            // ... Add whatever for Location
        }
    }
    

    SchoolFieldset

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

    SchoolForm

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

    前端

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

    请注意,这些文档不考虑删除(因此,如果你有id为0-1-2的HTML对象,你删除1,它将计数,来到2并创建另一个2,给你0-2-2因此覆盖你已经拥有的第二个) .

    我目前在一个项目中使用的JavaScript就是这个(抱歉,不能全部给你,但这应该让你开始):

    Buttons

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

    Usage

    $('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();
    }
    

    Note: "Remove"按钮放置在集合中的每个Fieldset中 . "Add another"按钮位于Collection下方 .

    你如何解决这个问题取决于你 .

    View

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

    Controller action

    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() ?: '',
        ];
    }
    

    ControllerFactory

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

    如果您有一些时间,我建议您查看我创建的回购中的更多示例,以帮助使用Doctrine快速创建ZF和ZF中的表单 . 自述文件的示例is here

相关问题