The delete row button only works after editing, not on first load

The delete row button only works after editing, not on first load

JammyClarkieJammyClarkie Posts: 6Questions: 2Answers: 1

There are no error messages on screen or on console.
When the datatable is loaded, if I select a row, then click on the delete button, the delete form shows. If I then click on the delete button within the delete form, nothing happens.

If I were to click the edit button first, close the edit form and then repeat the above, the delete button will then work as expected.

// data-tables-productsection.js
// set in base.html.twig
let sectionId = typeof entityId === "undefined" || !entityId ? {} : entityId;

var productEditor = new $.fn.dataTable.Editor({
    ajax: '/ajax/product-section-products/' + sectionId,
    fields: [
        {
            label: 'Ref:',
            name: 'ref'
        },
        {
            label: 'Name',
            name: 'name'
        }
    ]
})

var editor = new $.fn.dataTable.Editor( {
    ajax: '/ajax/product-section/' + sectionId,
    table: '#productsection-datatable',
    fields: [
        {
            label: "Rank:",
            name: "product_section.rank",
            fieldInfo: 'Enter an existing rank only.  It will become that rank and increase or decrease the ones inbetwen to make room.  Alternatively drag and drop.',
            attr: {
                type: 'number',
                min: 1,
                max: 999,
                step: 1
            }
        },
        {
            label: "Product:",
            name: "product_section.product_id",
            type: "datatable",
            editor: productEditor,
            optionsPair: { // needed to pre-select the product id
                value: "id"
            },
            config: {
                ajax: '/ajax/product-section-products/' + sectionId,
                columns: [
                    {
                        title: 'Ref:',
                        data: 'ref'
                    },
                    {
                        title: 'Name',
                        data: 'name'
                    }
                ]
            }
        },
        {
            label: "",
            name: "product_section.section_id",
            attr: {
                type: 'number',
                style: 'display:none;'
            },
            def: function() {
                return sectionId;
            }
        }
    ]
} );

// this event isn't triggered, but would be good for validating server side.
// editor.on('validatedCreate', function() {
//  console.log('here');
// });

editor

.on( 'postCreate postRemove postEdit', function () {
// After create or edit, a number of other rows might have been effected -
// so we need to reload the table, keeping the paging in the current position
table.ajax.reload( null, false );
} );

var table = $('#productsection-datatable').DataTable({
dom: 'Bfrtip',
ajax: '/ajax/product-section/' + sectionId,
paging: false,
rowReorder: {
dataSrc: 'product_section.rank',
editor: editor,
selector: 'td:first-child'
},
columns: [
{
data: null,
className: "dt-center w-5 reorder",
defaultContent: '<i class="dripicons-menu"></i>',
orderable: false
},
{
data: "product_section.rank",
className: "dt-center w-5",
orderable: true
},
{
data: "product.ref",
className: "",
orderable: false
},
{
data: "product.name",
className: "",
orderable: false
}
],
columnDefs: [

],
keys: true,
info: true,
select: true,
order: [[1, 'asc']],
buttons: [
    { extend: 'create', editor: editor, text: 'Add' },
    { extend: 'edit',   editor: editor },
    { extend: 'remove', editor: editor }
],

});

// DataTablesAjaxController.php

#[Route('/ajax/product-section/{section}')]
#[IsGranted('IS_AUTHENTICATED_REMEMBERED')]
public function productSection(Section $section, EntityManagerInterface $em, Request $request): Response
{
    $sectionId = $section->getId();
    $db = new Database(array(
        "type" => "Mysql",
        "pdo" => $em->getConnection()->getNativeConnection()
    ));

    $json =
        Editor::inst($db, 'product_section')
            ->fields(
                Field::inst('product_section.rank')
                    ->validator(Validate::notEmpty()),
                Field::inst('product_section.id'),
                Field::inst('product_section.product_id')
                    ->validator(Validate::notEmpty()),
                Field::inst('product_section.section_id'),
                Field::inst('product.ref'),
                Field::inst('product.name'),
                Field::inst('product.rank'),
                Field::inst('product.id'),
            )
            ->leftJoin('product', 'product_section.product_id', '=', 'product.id')
            ->where('section_id', $section->getId())
            ->on('preRemove', function ($editor, $id, $values) use ($sectionId) {
                // On remove, the sequence needs to be updated to decrement all rows
                // beyond the deleted row. Get the current reading order by id (don't
                // use the submitted value in case of a multi-row delete).
                $order = $editor->db()
                    ->select('product_section', 'rank', array('id' => $id))
                    ->fetch();

                $editor->db()
                    ->query('update', 'product_section')
                    ->set('rank', '`rank`-1', false)
                    ->where('rank', $order['rank'], '>')
                    ->and_where('section_id', $sectionId, '=')
                    ->exec();
            })
            ->on('preEdit', function ($editor, $id, $values) {
                // checks if we're editing via form or drag and drop.  name only present on editing form.
                if (isset($values['product_section']['product_id']) ?? false) {
                    $values = $values['product_section'];

                    $targetRank = (int)$values['rank'];
                    // check rank exists aleady
                    $order = $editor->db()
                        ->select('product_section', 'id', array('rank' => $targetRank))
                        ->fetch();
                    // don't allow user to enter a rank that doesn't already exist as this will create gaps
                    if ($order === false) {
                        return false;
                    }

                    $originalRank = (int)$editor->db()
                        ->select('product_section', 'rank', array('id' => $id))
                        ->fetch()['rank'];

                    if ($targetRank === $originalRank) {
                        return true;  // valid, but don't re-order anything
                    }

                    // higher rank (lower those inbetween to make room)
                    if ($targetRank > $originalRank) {
                        $editor->db()
                            ->query('update', 'product_section')
                            ->set('rank', '`rank`-1', false)
                            ->where('rank', $originalRank, '>')
                            ->and_where('rank', $targetRank, '<=')
                            ->and_where('section_id', (int)$values['section_id'], '=')
                            ->exec();
                    }

                    // lower rank (increase those inbetween to make room)
                    if ($originalRank > $targetRank) {
                        $editor->db()
                            ->query('update', 'product_section')
                            ->set('rank', '`rank`+1', false)
                            ->where('rank', $originalRank, '<')
                            ->and_where('rank', $targetRank, '>=')
                            ->and_where('section_id', (int)$values['section_id'], '=')
                            ->exec();
                    }
                }
            })
            ->on('preCreate', function ($editor, $values) {
                $values = $values['product_section'] ?? null;
                if (isset($values['product_section']['product_id']) ?? false) {
                    // If no value submitted, then use the max+1 as the new value
                    $next = $editor->db()->sql('select IFNULL(MAX(`rank`)+1, 1) as next FROM product_section WHERE section_id = ' . (int)$values['section_id'])->fetch();
                    $editor->field('rank')->setValue($next['next']);
                } else {
                    // On create update all the other records to make room for our new one
                    $editor->db()
                        ->query('update', 'product_section')
                        ->set('rank', '`rank`+1', false)
                        ->where('rank', $values['rank'], '>=')
                        ->and_where('section_id', (int)$values['section_id'], '=')
                        ->exec();
                }
            })
            ->process($_POST)
            ->json(false); // false to return the json instead of echo.

    return JsonResponse::fromJsonString($json);
}

This question has an accepted answers - jump to answer

Answers

  • kthorngrenkthorngren Posts: 21,315Questions: 26Answers: 4,948

    Do you see errors in the browser's console when clicking the delete button the first time?

    Is the ajax request sent to the server? If so what is the response?

    Can you post a link to your page or a test case showing the issue so we can help debug?
    https://datatables.net/manual/tech-notes/10#How-to-provide-a-test-case

    Kevin

  • JammyClarkieJammyClarkie Posts: 6Questions: 2Answers: 1

    Hi Kevin,

    No errors in the browser or console. No network requests sent, the button just doesn't seem to do anything!
    I can't provide a link at the moment because it's behind an admin area. I'll see if I can replicate the issue elsewhere. The difference between this datatable and others is that this one has a join to another table, so perhaps that's related.

  • kthorngrenkthorngren Posts: 21,315Questions: 26Answers: 4,948

    Possibly an element is in front of the button on the page.

    Kevin

  • JammyClarkieJammyClarkie Posts: 6Questions: 2Answers: 1
    Answer ✓

    I managed to resolve the issue - I had an event that was returning false incorrectly. Thanks for the help - it helped me find the issue.

  • JammyClarkieJammyClarkie Posts: 6Questions: 2Answers: 1

    I'm not sure how to close the question

  • allanallan Posts: 63,482Questions: 1Answers: 10,467 Site admin

    I've marked your answer as the accepted one :)

    Allan

Sign In or Register to comment.