Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Submitting Form Causes Error #27

Closed
thezenmonkey opened this issue May 15, 2018 · 14 comments
Closed

Submitting Form Causes Error #27

thezenmonkey opened this issue May 15, 2018 · 14 comments

Comments

@thezenmonkey
Copy link

thezenmonkey commented May 15, 2018

I have a contact form built in a UserForm Element. Upon submitting ElementalContentControllerExtension throws a User Error. Element $id not found for this page.

The ElementalPageExtension is applied to sub class of Page (CustomPage) if the helps.

PRs

@robbieaverill
Copy link
Contributor

Hi @thezenmonkey, could you please provide the versions of SilverStripe core, userforms, elemental and elemental-userforms that you're using?

@thezenmonkey
Copy link
Author

I'm using SS4.1 and the most current versions of the other modules. First thing I did when I saw the problem was run an update to see if that was it. So Elemental 2.1.0 Elemental UserForms 1.0.0 Userforms 5.1.1

I should also mention the form is sitting in a an Elemental List block (dev-master).

@thezenmonkey
Copy link
Author

For clarification the issue only occurs when the form element inside a Elemental List block

@boriscosic
Copy link

boriscosic commented Jun 2, 2018

@thezenmonkey we ran into the same issue using virtual element blocks. Our forms are structured in a block page and referenced via virtual element for reuse. We also wanted to submit the forms via ajax so during post we sent the request to block page holder and this seemed to work well. Seems like the issue is nesting forms inside anything other then Elemental Block. @robbieaverill

@Juanitou
Copy link

Juanitou commented Jun 5, 2018

The same happens when putting the form in a jQuery-UI modal dialog. I’m trying to find a solution…

@Juanitou
Copy link

Juanitou commented Jun 8, 2018

Sorry for the noise. My issue with the $id not being found was due to querying the Elemental user form from another page. The form works as expected if shown in the page where it is attached, whether it is in a modal window or not.

That said, there is another problem: the form is not working when another Elemental block is present in the page. But I’ll open another PR if I cannot find a solution.

Thanks!

@jinjie
Copy link

jinjie commented Sep 18, 2019

Facing similar issue.

Don't work

  • UserForm within ElementList
  • ElementList (UserForm) in ElementList

Works

  • UserForm at the root ElementArea

I think the issue is in ElementalContentControllerExtension.php

...
        foreach ($elementalAreaRelations as $elementalAreaRelation) {
            $element = $elementOwner->$elementalAreaRelation()->Elements()
                ->filter('ID', $id)
                ->First();

            if ($element) {
                return $element->getController();
            }
        }
...

Since $element is getting the elements directly from the owner, it actually doesn't look for more nested elements. Therefore, it can't find the element and returns the error.

Changing
$element = $elementOwner->$elementalAreaRelation()->Elements()
to
$element = BaseElement::get()
works...

@nathansams
Copy link

I ran into this issue myself. I was trying to use an ElementForm in a virtual element, which was what resulted in the present issue of not being able to find the element ID on the current page after submission.

After doing a little digging, it looks like the reason this error is occurring is because when you're using an element (ElementForm) within a parent element (e.g. an ElementList or an ElementVirtual), it's looking for the child element (the userform) on the current page, which it isn't a root element on. The Form() method on the ElementForm class sets the form action to the current controller's Link() URL (the one with the virtual element) and fails for the above reason.

The resolution for my case was to update the Form() method's action to retrieve the original element's owner Page's URL instead of the current controller's. Here's the update method in its entirety if it's useful in getting this bug resolved.

public function Form()
    {
        $controller = UserDefinedFormController::create($this);
        $current = Controller::curr();
        $controller->setRequest($current->getRequest());

        if ($current && $current->getAction() === 'finished') {
            return $controller->renderWith('App\Elements\ReceivedFormSubmission');
        }

        $owner_page = $this->owner->getPage();

        $segment = $owner_page->URLSegment === RootURLController::get_homepage_link() ? 'home' : $owner_page->RelativeLink();

        $form = $controller->Form();
        $form->setFormAction(
            Controller::join_links(
                $segment,
                'element',
                $this->owner->ID,
                'Form'
            )
        );

        return $form;
    }

You'll see there's a little bit of logic to deal with the original ElementForm being on the home page and ensuring the action contains /home in the URL (without which it will fail).

@michalkleiner
Copy link

michalkleiner commented Jan 23, 2020

@nathansams could you please create a PR for your update?

@muskie9
Copy link

muskie9 commented Jan 31, 2020

Would the preference for a PR to have it against the 3 branch or 3.0?

@jules0x
Copy link
Member

jules0x commented Mar 9, 2020

@nathansams I tried your solution and found that on submission, the "success" page was the page that the element was originally created on, not the page the virtual element sits on.

Less of a problem, I also found that the userdefinedforms jquery validation only comes through for the ElementForm, not the virtualised ElementForm.

@sukhwinder-somar
Copy link
Contributor

sukhwinder-somar commented Aug 15, 2023

Hi team, I had this same issue where I had a form inside of an element list and because currently ElementalContentControllerExtension.php (silverstripe-elemental) only check element on one level of a page so I have updated the code to also check in nested elements to match ID,

public function handleElement() 
    {
        $id = $this->owner->getRequest()->param('ID');

        if (!$id) {
            user_error('No element ID supplied', E_USER_ERROR);
            return false;
        }

        /** @var SiteTree $elementOwner */
        $elementOwner = $this->owner->data();

        $elementalAreaRelations = $this->owner->getElementalRelations();

        if (!$elementalAreaRelations) {
            user_error(get_class($this->owner) . ' has no ElementalArea relationships', E_USER_ERROR);
            return false;
        }

        foreach ($elementalAreaRelations as $elementalAreaRelation) {
            $element = $this->findElement($elementOwner->$elementalAreaRelation()->Elements(), $id);
    
            if ($element) {
                return $element->getController();
            }
        }
    
        user_error('Element $id not found for this page', E_USER_ERROR);
        return false;
    }

    private function findElement($elements, $id)
    {
        $element = $elements->filter('ID', $id)->First();

        if ($element) {
            return $element;
        }

        foreach ($elements as $el) {
            if (!$el->hasMethod('Elements')) {
                continue;
            }

            $subElementAreaRelations = $el->getElementalRelations();

            if (!$subElementAreaRelations) {
                continue;
            }

            foreach ($subElementAreaRelations as $subElementalAreaRelation) {
                $element = $this->findElement($el->$subElementalAreaRelation()->Elements(), $id);

                if ($element) {
                    return $element;
                }
            }
        }

        return null;
    }

and then I also have to update the finished function of this modules - src/Control/ElementFormController.php

public function finished()
    {
        $user = $this->getUserFormController();

        $user->finished();

        $page = $this->getPage();

        while(!$page instanceof SiteTree) {
            $page = $page->getPage();
        }

        $controller = Injector::inst()->create($page->getControllerName(), $page->data());
        $element = $this->element;

        return $controller->customise([
            'Content' => $element->renderWith($element->getRenderTemplates('_ReceivedFormSubmission')),
        ]);
    }

It seems to work fine.....

@GuySartorelli
Copy link
Collaborator

For some context about the error itself, the actual error thrown is

[User Error] Element $id not found for this page

It's thrown in ElementalContentControllerExtension.php:47

The stack trace is

ElementalContentControllerExtension.php:47
DNADesign\Elemental\Extensions\ElementalContentControllerExtension->handleElement
call_user_func_array
Extensible.php:147
SilverStripe\View\ViewableData->SilverStripe\Core\{closure}
CustomMethods.php:61
SilverStripe\View\ViewableData->__call
RequestHandler.php:323
SilverStripe\Control\RequestHandler->handleAction
Controller.php:286
SilverStripe\Control\Controller->handleAction
RequestHandler.php:202
SilverStripe\Control\RequestHandler->handleRequest
Controller.php:212
SilverStripe\Control\Controller->handleRequest
ContentController.php:251
SilverStripe\CMS\Controllers\ContentController->handleRequest
ModelAsController.php:101
SilverStripe\CMS\Controllers\ModelAsController->handleRequest
Director.php:361
SilverStripe\Control\Director->SilverStripe\Control\{closure}
VersionedHTTPMiddleware.php:41
..... middleware and the start of the request ommitted because it's irrelevant.

@GuySartorelli
Copy link
Collaborator

PRs merged. The relevant modules will be automatically tagged by GitHub actions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests