XF 2.0 Pass value from modal to page without page reload

CMTV

Well-known member
I have a page with the button "Add dependency" and hidden input field.
HTML:
<xf:button href="{{ link('UP/trophies/addDependency', $trophy) }}" class="button--add" icon="add" overlay="true">{{ phrase('UP_add_dependency') }}</xf:button>
<input name="page_dependencyValue" type="hidden" value="">

The button opens a modal:
PHP:
$viewParams = [
    'trophy' => $trophy
];

return $this->view('XF:Trophy\AddDependency', 'UP_add_trophy_dependency', $viewParams);

The modal consists of one textbox input field and submit button:
HTML:
<xf:title>{{ phrase('UP_add_dependency') }}</xf:title>

<xf:form action="{{ link('UP/trophies/addDependency', $trophy) }}" ajax="true" class="block">
    <div class="block-container">

        <div class="block-body">
            <xf:textboxrow name="dependencyValue"
                           label="{{ phrase('UP_trophy_link_or_id') }}"
                           hint="{{ phrase('UP_trophy_link_or_id_hint') }}" />
        </div>

        <xf:submitrow icon="add" submit="{{ phrase('add') }}" />
    </div>
</xf:form>

How can I pass dependencyValue from modal textbox field to page_dependencyValue field when clicking "Submit" button without reloading the page (without $this->redirect(...))?
I also have to perform some checkings and display errors if there are some. That is why I can't use class="js-overlayClose" as it always closes the modal even if there are some errors (it shows the error but closes the modal).

Basically, how can I check dependencyValue value on backend when clicking "Submit", then close the modal and pass the value of dependencyValue to page_dependencyValue without reloading the page?
 

Mike

XenForo developer
Staff member
You will likely need a custom JS handler here to handle the cases/data that you need.
 

CMTV

Well-known member
Ok. I found a way to close the modal without reloading the page:
HTML:
<xf:form action="{{ link('UP/trophies/addDependency', $trophy) }}" ajax="true"
         data-reset-complete="true" data-redirect="off" class="block">

Is there a way to launch JS script after ajax request?
 

CMTV

Well-known member
Here is the solution.

First of all, we need to add data-redirect="off" and data-xf-init="add-dependency" attributes to <xf:form action... tag in the modal:
HTML:
<xf:form action="{{ link('UP/trophies/addDependency', $trophy) }}" ajax="true"
         data-redirect="off" class="block"
         data-xf-init="add-dependency">
...
    <xf:submitrow icon="add" submit="{{ phrase('add') }}" />
...
</xf:form>

  • data-redirect="off" - preventing page reload when submitting the modal
  • data-xf-init="add-dependency" - specifying ajax response (with values from modal fields) catcher (will be explained below)

In controller method actionAddDependency use this code:
PHP:
public function actionAddDependency(ParameterBag $params)
{
    // Making sure we clicked "Submit"
    if($this->isPost())
    {
        // Filtering values from your modal

        // Checking things and displaying errors

        $redirect = $this->redirect($this->buildLink('UP/trophies/edit', $trophy));

        // Set a value you want to pass back to page
        $redirect->setJsonParam('testParam', $dependencyId);

        return $redirect;
    }
}

Now we need to create JS handler for catching ajax response when clicking "Submit" in modal.
In my case I created javascript file add_dependency.js:
JavaScript:
!function($, window, document, _undefined)
{
    "use strict";

    XF.UP_AddDependency = XF.Element.newHandler({

        options: {},

        init: function()
        {
            var $form = this.$target;

            $form.on('ajax-submit:response', $.proxy(this, 'ajaxResponse'));
        },

        ajaxResponse: function(e, data)
        {
            $("input[name='page_dependencyValue']").val(data.testParam);
        }
    });

    // "add-dependency" must be equal with "data-xf-init" attribute value we set above
    XF.Element.register('add-dependency', 'XF.UP_AddDependency');
}
(jQuery, window, document);

This line
JavaScript:
$("input[name='page_dependencyValue']").val(data.testParam);
sets a value of hidden input value on the page using the value of testParam we passed in controller action before.

Don't forget to include js handler in modal template:
HTML:
<xf:js src="UserProgression/add_dependency.js" addon="UserProgression" />

That's it! You can now pass values from modals to page without reloading with an ability to perform checkings and display errors in action... controller method.
 
Last edited:

asprin

Active member
Sorry for the bump, but very helpful thread. Learned some things which weren't known to me. Thanks for sharing the explanation.
 
Top