PHPackages                             heimrichhannot/contao-list-widget-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. heimrichhannot/contao-list-widget-bundle

ActiveContao-bundle[Utility &amp; Helpers](/categories/utility)

heimrichhannot/contao-list-widget-bundle
========================================

This bundle offers an input type for displaying a list of entities definable by a callback function.

1.5.3(8mo ago)02.8k↓33.3%1LGPL-3.0-or-laterPHPPHP ^8.1CI passing

Since Dec 4Pushed 8mo ago4 watchersCompare

[ Source](https://github.com/heimrichhannot/contao-list-widget-bundle)[ Packagist](https://packagist.org/packages/heimrichhannot/contao-list-widget-bundle)[ Docs](https://github.com/heimrichhannot/contao-list-widget-bundle)[ RSS](/packages/heimrichhannot-contao-list-widget-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (13)Versions (19)Used By (1)

Contao List Widget
==================

[](#contao-list-widget)

This bundle offers functionality for displaying a list in the Contao backend (either as a dca field or in a backend module).

For visualization the javascript library [DataTables](https://github.com/DataTables/DataTables) is used.

[![alt text](./docs/screenshot.png "Demo in the backend")](./docs/screenshot.png)

Features
--------

[](#features)

- inputType "listWidget" for usage as a dca field
- convenient functions for integrating a list in your backend module
- the list can display either model data or even arbitrary arrays
- support for datatables javascript library
    - filter the table
    - search the table
    - sort the table
- support for ajax reloading data using datatables -&gt; currently only working for contao models since SQL-commands like LIMIT are used

Technical instructions
----------------------

[](#technical-instructions)

### Usage as a widget in a dca field

[](#usage-as-a-widget-in-a-dca-field)

Use the inputType "listWidget" for your field.

```
'someField' => [
    'label'     => &$GLOBALS['TL_LANG']['tl_my_dca']['someField'],
    'exclude'   => true,
    'inputType' => 'listWidget',
    'eval'      => [
        'listWidget' => [
            'ajax'                   => true,
            'ajaxConfig'             => [
                'load_items_callback' => ['SomeClass', 'loadItems']
            ],
            'header_fields_callback' => function ()
            {
                $arrHeaderFields = [];

                foreach (['academicTitle', 'additionalTitle', 'gender', 'lastname', 'email'] as $strField)
                {
                    $arrHeaderFields[$strField] = \HeimrichHannot\Haste\Dca\General::getLocalizedFieldname($strField, 'tl_dca');
                }

                return $arrHeaderFields;
            },
            'table'                  => 'tl_dca'
        ]
    ]
]

```

### Usage in a module

[](#usage-in-a-module)

Add the following code e.g. in the generate() method of your BackendModule:

```
static::$arrListConfig = [
    'identifier' => 'module_' . $this->id,
    'table' => 'tl_dca',
    'ajax' => true,
    'ajaxConfig' => [
        'load_items_callback' => function($arrConfig, $arrOptions = [], $objContext = null, $objDc = null) {
            return $this->loadItems($arrConfig, $arrOptions, $objContext, $objDc);
        },
        'prepare_items_callback' => function($objItems) {
            return $this->parseNewsletters($objItems);
        },
    ],
    'columns' => static::getColumns(),
    'language' => static::getLanguage()
];

static::$arrListConfig = ListWidget::prepareConfig(static::$arrListConfig, $this);

ListWidget::initAjaxLoading(static::$arrListConfig);

```

Call this in your module's compile method:

```
ListWidget::addToTemplate($this->Template, static::$arrListOptions);

```

Copy the content of list\_widget.html5 into your module's template.

### Using ajax with custom routes

[](#using-ajax-with-custom-routes)

Since version 1.3 it is possible to use custom routes for ajax requests to have more control or freedom over the returned data. Use `ListWidgetContext` class as helper to process the request and return a `ListWidgetResponse` object.

```
# /contao/dca/tl_custom.php
$GLOBALS['TL_DCA']['tl_custom']['fields']['people'] = [
  'inputType' => 'listWidget',
  'eval' => [
      'tl_class' => 'long clr',
      'listWidget' => [
          'ajax' => true,
          'ajaxConfig' => [
              'route' => 'app_list_widget_people_list',
          ],
          'table' => 'tl_custom',
      ],
  ],
];

# /src/Controller/PeopleController.php

use Contao\CoreBundle\Framework\ContaoFramework;
use Doctrine\Common\Collections\Criteria;
use HeimrichHannot\ListWidgetBundle\Controller\ListWidgetContext;
use HeimrichHannot\ListWidgetBundle\Controller\ListWidgetResponse;
use App\People\PeopleFinder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

#[Route('/app/list_widget/people_list', name: 'app_list_widget_people_list', defaults: ['_scope' => 'backend'])]
class PeopleController
{
    public function __construct(
        private readonly ContaoFramework $framework,
        private readonly PeopleFinder $people,
    ) {}

    public function __invoke(Request $request): ListWidgetResponse
    {
        $this->framework->initialize();
        try {
            $context = ListWidgetContext::createFromRequest($request);
        } catch (\Exception $e) {
            return new ListWidgetResponse(1, 0, 0, [], $e->getMessage());
        }

        $countTotal = $this->people->countByList($context->id);
        $fields = ['id', 'email', 'firstname', 'lastname'];

        $criteria = new Criteria();
        $context->applySearchToCriteria($criteria,$fields);
        $countFiltered = $this->people->countByList($context->id, $criteria);
        $context->applyListConfigToCriteria($criteria, $fields);
        $people = $this->people->findByList($context->id, $fields, $criteria);
        return $context->createResponse($countTotal, $countFiltered, $people);
    }
}
```

### Example load\_items\_callback

[](#example-load_items_callback)

Here you can see an example for overriding the core behavior of loadItems():

```
public static function loadItemsNew($arrConfig, $arrOptions = [], $objContext = null, $objDc = null)
{
    // set an initial filter using the contao options array
    $arrOptions = [
        'table'   => $arrConfig['table'],
        'columns' => $arrConfig['columns'],
        // filtering
        'column'  => 'pid',
        'value'   => $objDc->id
    ];

    // the rest of the function should also be called
    return ListWidget::loadItems($arrConfig, $arrOptions, $objContext, $objDc);
}

```

### Config (same structure for DCA -&gt; eval -&gt; listWidget and shortcut functions)

[](#config-same-structure-for-dca---eval---listwidget-and-shortcut-functions)

NamePossible valueDescriptionidentifierstringNeeded for distinguishing requests from multiple list widget implementations, e.g. `'module_' . $this->id`headerFieldsarrayMust return an array containing the header fields. The keys must match the keys of the arrays/objects in items/items\_callback.header\_fields\_callbackcallback array, function closureMust return an array containing the header fields. The keys must match the keys of the arrays/objects in items/items\_callback.itemsarrayMust return an array containing the items to be displayed. The item keys must match those in header\_fields/header\_fields\_callback.items\_callbackcallback array, function closureMust return an array containing the items to be displayed. The item keys must match those in header\_fields/header\_fields\_callback.tablestring (e.g. "tl\_dca")This value is needed for useDbAsHeader and ajax handlinguseDbAsHeaderbooleanSet to true if the header should contain all fields of a certain database entity ("table" is used)templatestringSpecify a custom templatelanguagearraySpecify custom localizations (see ListWidget::getLanguage() for details)language\_callbackcallback array, function closureSpecify custom localizations (see ListWidget::getLanguage() for details)ajaxbooleanSet to true if ajax reloading should take place (no need for items\_callback in this case)ajaxConfig -&gt; load\_itemsarrayOverride this if custom model options or methods are needed (see ListWidget::loadItems() for details)ajaxConfig -&gt; load\_items\_callbackcallback array, function closureOverride this if custom model options or methods are needed (see ListWidget::loadItems() for details)ajaxConfig -&gt; prepare\_itemsarrayOverride this if custom data preparation is needed (see ListWidget::prepareItems() for details)ajaxConfig -&gt; prepare\_items\_callbackcallback array, function closureOverride this if custom data preparation is needed (see ListWidget::prepareItems() for details)### Callbacks

[](#callbacks)

NameArgumentsExpected return valueDescriptionheaderFields\_callback$objDc, $arrDca, $objWidgetarray containing field and label pairs (`['field1' => 'fieldLabel1', 'field2' => 'fieldLabel2', ...]`)This callback must return the headerFields to be displayed in the list. Array keys need to be the keys in items\_callback (see list\_widget.html5 for explanation).items\_callback$objDc, $arrDca, $objWidgetarray of entity arrays (`[['field1' => 'value1', 'field2' => 'value2'], ...]`)This callback must return the items to be displayed in the listload\_callback$arrOptions, \[\], $objDc, $arrDca, $objWidgetdata array (see ListWidget::loadItems for more details)Override this method if custom model options or methods are neededprepare\_items\_callback$objItems, $arrListOptions, $arrOptions, $objDc, $arrDca, $objWidgetdata array (see ListWidget::prepareItems for more details)Override this method if custom data preparation is needed

###  Health Score

45

—

FairBetter than 93% of packages

Maintenance62

Regular maintenance activity

Popularity21

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~116 days

Recently: every ~50 days

Total

16

Last Release

242d ago

PHP version history (4 changes)1.0.0PHP ^7.2

1.1.0PHP ^7.2 || ^8.0

1.3.0-alpha1PHP ^8.2

1.3.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/28ad3224d8727b622ebd229840eea6b9dbcb83eb0bd609e6ce65b614830ff538?d=identicon)[digitales@heimrich-hannot.de](/maintainers/digitales@heimrich-hannot.de)

---

Top Contributors

[![koertho](https://avatars.githubusercontent.com/u/12064642?v=4)](https://github.com/koertho "koertho (21 commits)")

###  Code Quality

Static AnalysisPHPStan, Rector

Code StyleECS

Type Coverage Yes

### Embed Badge

![Health badge](/badges/heimrichhannot-contao-list-widget-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/heimrichhannot-contao-list-widget-bundle/health.svg)](https://phpackages.com/packages/heimrichhannot-contao-list-widget-bundle)
```

###  Alternatives

[codefog/contao-haste

haste extension for Contao Open Source CMS

42650.8k139](/packages/codefog-contao-haste)[codefog/contao-news_categories

News Categories bundle for Contao Open Source CMS

3183.3k6](/packages/codefog-contao-news-categories)[numero2/contao-storelocator

Contao Plugin for managing stores (or in common address data) and providing a frontend-search based on geo data

121.5k](/packages/numero2-contao-storelocator)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
