-->

Add/Create Element to ObjectStorage using Javascri

2019-05-14 00:22发布

问题:

what is the correct way to dynamically create new Child Elements in a Fluid Form using JavaScript?

Problem: 1:n Relation (Parent/Child) using Extbase ObjectStorages: When the Parent Fluid Form is called it should be possible to add several childs (incl. properties of course!)

Dirty, partly working, Solution: I added some JS Code and added the required input elements dynamically. The "xxx" will be interated for each Child. The data will be correctly stored in the DB.

<input type="text" placeholder="First Name" name="tx_booking[newBooking][accompanyingperson][xxx][firstname]">

However, if an error occurres all child forms disappear and no f3-form-error will be shown. The reason for this, may be the redirect to originalRequest (initial form without child fields).

How can I handle this Problem without dirty tricks? Please give me shirt hint.

回答1:

Again, I will answer the question myself! The following lines are the foulest code ever but it works. I really want to know how to do this in a correct way. However, the solution is, to get the Arguments from the dynamically added JS Inputs. This is done in the errorAction and will be passed by the forward() to the initial Action, where the Errors should be appear.

I for all think, that must be a better way by using the PropertyMapper and modify the trustedProperties....

Here a short example:

    // Error function in Controller

protected function errorAction() {

    $referringRequest = $this->request->getReferringRequest();

    // Manual added JS Data
    if($this->request->hasArgument('newRegistration'))
    {
        $newRegistration = $this->request->getArgument('newRegistration');
        $referringRequest->setArgument('accompanyingperson', $newRegistration['accompanyingperson']);
    }

     if ($referringRequest !== NULL) {
        $originalRequest = clone $this->request;
        $this->request->setOriginalRequest($originalRequest);
        $this->request->setOriginalRequestMappingResults($this->arguments->getValidationResults());
        $this->forward($referringRequest->getControllerActionName(), $referringRequest->getControllerName(), $referringRequest->getControllerExtensionName(), $referringRequest->getArguments());

    }
}


// action new in Controller
public function newAction(\***\***\Domain\Model\Registration $newRegistration = NULL) {
    if($this->request->hasArgument('accompanyingperson'))
    {
        $this->view->assign('accPer', $this->request->getArgument('accompanyingperson'));
    }
    .
    .
    .
}


//Fluid template of Action New
<f:if condition="{accPer}">
    <f:for each="{accPer}" as="ap" key="key" iteration="i">
        <f:form.textfield class="form-control" placeholder="First Name" property="accompanyingperson.{key}.firstname"/>
        .
        .
        .
    </f:for>
</f:if>


回答2:

Following is my solution, something like yours.

Models

class Resume extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
    /**
     * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<Builder>
     * @cascade remove
     */
    protected $builders;
}

class Builder extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
    /**
     * @var string
     */
    protected $title;
}

Controller

class ResumeController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
    /**
     * @var \Dagou\Resume\Domain\Repository\ResumeRepository
     * @inject
     */
    protected $resumeRepository;

    /**
     * @param \Dagou\Resume\Domain\Model\Resume $resume
     * @see \Dagou\Resume\Controller\ResumeController::saveAction()
     */
    protected function createAction(\Dagou\Resume\Domain\Model\Resume $resume = NULL) {
        $this->view->assignMultiple([
            'resume' => $resume,
        ]);
    }

    protected function initializeCreateAction() {
        if (($request = $this->request->getOriginalRequest())) {
            $this->request->setArgument('resume', $request->getArgument('resume'));

            $propertyMappingConfiguration = $this->arguments->getArgument('resume')->getPropertyMappingConfiguration();

            $propertyMappingConfiguration->allowCreationForSubProperty('builders.*');

            $propertyMappingConfiguration->allowProperties('builders')
                ->forProperty('builders')->allowAllProperties()
                    ->forProperty('*')->allowAllProperties();
        }
    }

    protected function initializeSaveAction() {
        $propertyMappingConfiguration = $this->arguments->getArgument('resume')->getPropertyMappingConfiguration();

        $propertyMappingConfiguration->allowCreationForSubProperty('builders.*');

        $propertyMappingConfiguration->allowProperties('builders')
            ->forProperty('builders')->allowAllProperties()
                ->forProperty('*')->allowAllProperties();
        }
    }

    /**
     * @param \Dagou\Resume\Domain\Model\Resume $resume
     */
    protected function saveAction(\Dagou\Resume\Domain\Model\Resume $resume) {
        $this->resumeRepository->add($resume);
    }
}

Template

<f:form class="form-horizontal" name="resume" action="save" object="{resume}">
    <f:if condition="{resume.builders}">
        <f:for each="{resume.builders}" as="builder" iteration="builderIteration">
            <f:form.textfield class="form-control" property="builders.{builderIteration.index}.header" />
        </f:for>
    </f:if>
</f:form>

If you have a better one, please let me know. Thanks!



标签: typo3 extbase