Dropdown for N-to-N gets cut off in modal

Consider the following database design, a classic example of books and authors related to each other really:

CREATE TABLE author
             (id integer
			     GENERATED ALWAYS AS IDENTITY,
			  name text
			       NOT NULL,
			  PRIMARY KEY (id));

CREATE TABLE book
             (id integer
			     GENERATED ALWAYS AS IDENTITY,
			  name text
			       NOT NULL,
			  PRIMARY KEY (id));

CREATE TABLE book_author
             (book integer,
			  author integer,
			  PRIMARY KEY (book,
						   author),
			  FOREIGN KEY (book)
			              REFERENCES book
			                         (id)
			              ON DELETE CASCADE,
			  FOREIGN KEY (author)
			              REFERENCES author
			                         (id)
			              ON DELETE CASCADE);

INSERT INTO author
            (name)
			VALUES ('John'),
			       ('Thomas'),
				   ('Peter'),
				   ('Maria'),
				   ('Henry'),
				   ('Jane'),
				   ('Mary'),
				   ('Steve'),
				   ('Kathy'),
				   ('Mark'),
				   ('Sonja'),
				   ('Carol');

This is code for Postgres but it should be simple enough to adapt it for any engine easily.

Using the latest Enterprise v2.9.6 our controller Book.php for managing the books looks like this, again really simple more or less straight out of the examples in the documentation:

<?php

namespace App\Controllers;

include(APPPATH . 'Libraries/GroceryCrudEnterprise/autoload.php');
use GroceryCrud\Core\GroceryCrud;

class Book extends BaseController
{
    private function _getDbData()
    {
        return ['adapter' => ['driver' => 'Pdo_Pgsql',
                              'host' => '127.0.0.1',
                              'port' => 5432,
                              'database' => 'db',
                              'username' => 'user',
                              'password' => 'pass']];
    }

    protected function _getGroceryCrudEnterprise($bootstrap = true, $jquery = true)
    {
        $db = $this->_getDbData();

        $config = (new \Config\GroceryCrudEnterprise())->getDefaultConfig();

        $groceryCrud = new GroceryCrud($config, $db);

        $groceryCrud->setCsrfTokenName(csrf_token());
        $groceryCrud->setCsrfTokenValue(csrf_hash());

        return $groceryCrud;
    }

    protected function _output($output = null, $title = null)
    {
        $output->title = $title;

        if (isset($output->isJSONResponse)
            && $output->isJSONResponse) {
            header('Content-Type: application/json; charset=utf-8');
            echo $output->output;
            exit;
        }

        return view('book', (array)$output);
    }

    public function index()
    {
        $crud = $this->_getGroceryCrudEnterprise();

        $crud->setTable('book');
        $crud->setSubject('Book', 'Books');

        $crud->setRelationNtoN('authors', 'book_author', 'author', 'book', 'author', 'name', 'name');
        $crud->columns(['name', 'authors']);
        $crud->fields(['name', 'authors']);
        $crud->requiredFields(['name', 'authors']);

        $output = $crud->render();

        return $this->_output($output, 'Books');
    }
}

Note that we use setRelationNtoN() to set the relation between books and authors. And again this assumes the DBMS to be Postgres, change the connection settings if needed.

The view book.php is quite simple and near to the examples too:

<!DOCTYPE html>
<html>
<head>
    <title>
        <?php echo "$title"; ?>
    </title>
	<meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <?php foreach($css_files as $file): ?>
	<link type="text/css" rel="stylesheet" href="<?php echo $file; ?>" />
    <?php endforeach; ?>
</head>
    <div>
		<?php echo $output; ?>
    </div>
    <?php foreach($js_files as $file): ?>
    <script src="<?php echo $file; ?>">
    </script>
    <?php endforeach; ?>
</body>
</html>

Assuming an underlying CodeIgniter app the controller gets stored in app/Controllers/Book.php, the view in app/Views/book.php. There are the following routes in app/Config/Routes.php:

...

$routes->get('/book', 'Book::index');
$routes->post('/book', 'Book::index');
$routes->get('/book/(:any)', 'Book::index/$1');
$routes->post('/book/(:any)', 'Book::index/$1');

...

Grocery is set to use modals – 'open_in_modal' => true in app/Config/GroceryCrudEnterprise.php – and we use the latest Bootstrap V5 Theme v1.5.3 – 'skin' => 'bootstrap-v5' in app/Config/GroceryCrudEnterprise.php.

Now when we add a new book (or analogue if we edit an existing one) this is how it gets rendered in Firefox 109.0:


Looks pretty nice!

But there is a problem. The list of authors is cut off at the bottom even though there is plenty of space left on the screen. There is no chance to reach the lower authors using the mouse. The wheel won’t do it and if we try to click the scrollbar on the right of the modal it instantly disappears (because that closes the dropdown and shortens the modal’s content to a point where the scrollbar is no longer needed), so we cannot use that either.
It is possible to use the down key on the keyboard to reach lower authors but since the lower part of the dropdown keeps hidden, we cannot see what author we’re at. So that won’t really help either, let alone that most users prefer to use the mouse.

It is a bit better in Chrome 109.0.5414.120 and Edge 109.0.1518.70. At least the scrollbar on the right of the modal doesn’t disappear so we can scroll down the modal’s content but only after we’ve opened the dropdown for the first time and then get back into the dropdown and navigate it. But that’s at least cumbersome.

Is there a way to get this working properly, so that it can be used with the mouse and useful navigation is possible in the dropdown right away? While still using modals that is of course. The full page form when modals are switched off hasn’t got the problem. But it would be neater to use modals.

1 Like