3

For my TYPO3 Extbase Extension I want to do some kind of pagination. The ajax call and everything else is fine so far. But when I try to access the $this->settings Array during the ajax call, where the flexform frontend plugin values are stored, I always get null. The part looks like this:

$limit = $this->settings['result']['amount'];
$orderType = $this->settings['order']['type'];
$orderFields = $this->settings['additionorder']['fields'];

$formArr = array();
$this->request->hasArgument('offset') ? $offset = $this->request->getArgument('offset') : null;
$forms = $this->formRepository->findFormsChunked(
$orderFields, $orderType, $limit, $offset
);

foreach ($forms as $key => $form) {
         $formArr[] = array(
                    'formUid' => $form->getUid(),
                    'formName' => $form->getName(),
                    'formFile' => $form->getFile()->getOriginalResource()->getPublicUrl(),
                    'formType' => $form->getFormtype()->getUid()
                );
            }
 return json_encode($formArr);

And $this->settings is null during my ajax call, but I can't imagine why. Are the values only available during the rendering process, which is not happening during the ajax call?

Thanks for the help.

UPDATE

As far as I know, the flexform values are only passed to the selected controller-actions (i.e. displaycond) like this:

 <displayCond>FIELD:switchableControllerActions:=:Controller->ajax:AND:FIELD:switchableControllerActions:=:Controller->normal</displayCond>

and in the select menu:

                               <numIndex index="1">
                                    <numIndex index="0">LLL:EXT:ext_formpool/Resources/Private/Language/locallang.xlf:name</numIndex>
                                    <numIndex index="1">Controller->normal;Controller->ajax</numIndex>
                                </numIndex>

So the values should be passed to the ajaxAction too? At the moment they are not available...

Solution

Unfortunately, it simply doesn't work if you do ajax calls with a separate page type. The flexform is stored in the database and gets only parsed during the framework-loading process. You can check this by including the configuration manager and try to parse the content object's "pi_flexform" field. Or you inject the flexformservice, which is also not loaded during the ajax call. You have to use the eID-mechanism to achieve this.

TheFlame
  • 57
  • 1
  • 7
  • 1
    How do you do the AJAX call? Using eID, a page type, or Helmut Hummels extension [typoscript_rendering](http://typo3.org/extensions/repository/view/typoscript_rendering)? – Jost Jun 29 '15 at 11:54
  • 1
    I'm using ajax with included page type like this: `# Pagetype for AjaxCalls ajaxCall = PAGE ajaxCall { typeNum = 999 config.disableAllHeaderCode = 1 config.metaCharset = UTF-8 10 = COA 10 < tt_content.list.20.myext }` – TheFlame Jun 29 '15 at 16:25

5 Answers5

3

We solved this by adding the uid of the plugin (content element) to the URL for the Ajax request and then loading the flexform configuration using the FlexFormService.

Build URL in Controller:

$url = $this->uriBuilder->setTargetPageType(1234)->uriFor(
    'ajaxAction',
    [
        'contentUid' => (int) $this->configurationManager->getContentObject()->data['uid']
    ]
);

Initialize Controller actions by setting flexform settings:

class SomeController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
    protected $flexFormService;
    protected $flexformSettings = [];

    public function injectFlexFormService(\TYPO3\CMS\Extbase\Service\FlexFormService $flexFormService): void
    {
        $this->flexFormService = $flexFormService;
    }

    public function initializeAction(): void
    {
        parent::initializeAction();

        if ($this->request->hasArgument('contentUid')) {
            $recordUid = (int) $this->request->getArgument('contentUid');
            $record = TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('tt_content', $recordUid, 'pi_flexform');

            if (!empty($record['pi_flexform'])) {
                $this->flexformSettings = $this->flexFormService->convertFlexFormContentToArray($record['pi_flexform']);
            }
        }
    }

    public function ajaxAction(): void
    {
        //access $this->flexformSettings;
    }
}
maechler
  • 1,257
  • 13
  • 18
2

I had this problem too, than I found out you need to use renderObj which will use the ContentObjectRenderer class. I needed the Flexform value for the f:link to the detailpage from my list template.

So in my case, I also wanted Ajax pagination. I just used the default Fluid paginate widget in the list view of my own news extension. If the client has no javascript it then still works. So it's really easy to create cool Ajax pagination!

Typoscript for the typeNum:

ajaxPageExt = PAGE
ajaxPageExt {
    typeNum = 778

    config {
        disableAllHeaderCode = 1
        disableCharsetHeader = 1
        disablePrefixComment = 1
    }

    10 < styles.content.get
    10 {
        stdWrap.trim = 1
        select {
            where = list_type = "jpnews_list"
        }

        renderObj < tt_content.list.20.jpnews_list
    }
}

A part of possible javascript:

              $('body').on('click', 'div.jpnews-list ul.f3-widget-paginator li a', (function (e) {
                    e.preventDefault();
                    paginateToPageURI = $(this).attr('href') + '&type=' + TYPO3pageType;
                    var parentDivOfNewsList = $(txJpNews).parent();
                    $(txJpNews).css('opacity', 0.4);
                    $(parentDivOfNewsList).append(spinnerHTML);
                    $.ajax({
                        type: 'POST',
                        url: paginateToPageURI,
                        data: $(this).serializeArray(),
                        success: function (data) {
                            $(parentDivOfNewsList).html(data);
                        },
                        error: function (xhr, thrownError) {
                            var msg = "<b>Sorry but there was an error, please contact us..</b><br>";
                            $(parentDivOfNewsList).html(msg + xhr.status + ' ' + thrownError);
                        }
                    });
                })
1

why not, instead of render your plugin as a content object, directly address it in your ajax call?

plugin_yourext_ajax = PAGE
plugin_yourext_ajax {
    typeNum = 2000

    config {
        disableAllHeaderCode = 1
        xhtml_cleaning = 1
        admPanel = 0
        additionalHeaders = Content-type: text/plain
        no_cache = 1
    }

    10 = USER
    10 {
        userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
        pluginName = YourPLugin
        extensionName = YourExt
        controller = ControllerName
        vendorName = Vendor
        action = ajax

        switchableControllerActions {
            YourPlugin {
                1 = ajax
            }
        }

        persistence =< plugin.tx_your_ext.persistence
        view =< plugin.tx_your_ext.view
        update =< plugin.tx_your_ext.update
        settings < plugin.tx_your_ext.settings
    }
}

This will bootstrap your extension on every call, instead of pagerendering

rob-ot
  • 1,264
  • 8
  • 10
0

Do you declare your flexforms in your ext_tables.php? I normally do it like this:

$extensionName = t3lib_div::underscoredToUpperCamelCase($_EXTKEY);
$pluginNames = array('pluginname1','pluginname2','...');

foreach ($pluginNames as $pluginName) {
    $pluginSignature = strtolower($extensionName) . '_'.$pluginName;

    $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_excludelist'][$pluginSignature] = 'recursive';
    $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist'][$pluginSignature] = 'pi_flexform';
    t3lib_extMgm::addPiFlexFormValue($pluginSignature, 'FILE:EXT:' . $_EXTKEY . '/Configuration/FlexForms/'.$pluginName.'.xml');
}
Jay Dinse
  • 504
  • 4
  • 19
  • Yes, my DownloadController gets the Flexform data, however, only during the ajax call $this->settings is empty (except those constants I declared in my ext_setup). Possibly it has to do with the rendering process as @rob-ot mentioned. – TheFlame Jun 30 '15 at 07:54
  • if $this->settings is empty, you didn't inject it properly OR your declaration is wrong. check your TS. if normal calling of your controller action results in NULL for settings then this might be the clue : settings < plugin.tx_your_ext.settings – rob-ot Jun 30 '15 at 12:48
  • How do you access the Flexform values then? The settings array does contain all extension-configurations except the Flexform ones. – TheFlame Jul 01 '15 at 15:12
  • According to your ajax example above, normally they are stored in $this->settings, too. – TheFlame Jul 01 '15 at 15:28
  • That is weird. I normally had the opposite problem, meaning that as soon as I use FlexForms the extension-configuration set by TS is not available anymore. In your case I guess that you only get the extension-configuration with `settings < plugin.tx_your_ext.settings`. You could use the Object-Browser to investigate your TS more deeply. – Jay Dinse Jul 01 '15 at 15:58
  • Just an idea: does `settings =< plugin.tx_your_ext.settings` help? – Jay Dinse Jul 01 '15 at 16:00
  • Unfortunately, it only displays the extension settings. Defining an own page type has obviously the disadvantage that the framework configuration is not loaded in. The Flexform is stored in the database and gets never parsed without the framework configuration... so, this might be the problem, if I use Javascript with a page type and not with eID - quite disappointing. – TheFlame Jul 02 '15 at 14:03
0

I think rob-ot´s anwer is a bit outdated and relies on css styled content (?) Rendering the content element itself in the ajax call in my opinion is still the easiest option, but this is the way to go now (At least for Typo3 10.4):

ajaxPageExt = PAGE
ajaxPageExt {
    typeNum = 1234

    config {
        disableAllHeaderCode = 1
    }

    10 = CONTENT
    10 {
        pidInList = this
        table = tt_content
        select {
            where = CType = 'your_plugin_ctype'
        }
        # Can be omitted, because it is the default
        # renderObj < tt_content
    }
}

In your ajax url, you do not necessarily have to add control nor action parameters anymore. It could look like so:

index.php?id=4321&type=1234

Note that this has some restrictions. In case there are multiple elements of the given CType on the page, all of them would be rendered. Picking one of them by adding a content_uid parameter to the url and then using it in the TypoScript via GP : content_uid is not recommendable because of the risk of SQL injections.

klawipo
  • 153
  • 5