Zend Framework 3 — Добавить и удалить новый раздел элемента ввода, используя JavaScript

Я хочу добавить несколько школьных локаций в Zend-форму по щелчку якорного тега или кнопки.
Так что проверка формы Zend может быть применена ко всем динамически создаваемым полям
Пожалуйста, смотрите прикрепленное изображение. Я хочу клонировать div с красной рамкой в ​​изображении
введите описание изображения здесь

Ниже класс 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 -->

Я хочу клонировать DIV с классом школьного размещения

Заметка*: Я попробовал приведенные ниже решения, но у меня ничего не получилось, так как они не являются решением для Zend Framework-3.

  1. Zend Framework — Добавить новый элемент ввода, используя JavaScript

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

3

Решение

То, что вы ищете, это использование Коллекции (который вы связали) и Fieldsets.

Вы используете Fieldset для представления сущности. В этом примере Fieldset Locationприлагается к School,

Так же School как One To Many связь с Location,

Таким образом, у вас будет SchoolFieldset класс, который нуждается в Collection Элемент.

Ниже приведен очень упрощенный пример настройки.

Backend

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.

Обратите внимание, что эти документы не учитывают удаление (поэтому, если у вас есть HTML-объекты с идентификаторами 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();
}

Замечания: кнопка «Удалить» находится в каждом наборе полей в коллекции. Кнопка «Добавить еще» находится под коллекцией.

Как вы решите эту проблему, зависит от вас.

Посмотреть

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

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

Если у вас есть несколько свободных моментов, я бы посоветовал вам проверить другие примеры в репозитории, который я создал, чтобы помочь быстро создавать формы в ZF и ZF с Doctrine. ReadMe с примерами это здесь

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]