Conditional delete of repeat groups entries

mauro

Member
Hi Fabrik community,
I'm learning to use repeat groups to allow the user to edit (in the same form) a record from a master table and all its related rows from a detail table. I think it's very cool feature but now I have a problem I don't know how to manage...

In the form with repeat groups, I would like to make a validation check so that the user should not be allowed to delete a detail row (repeat group) if some conditions are not met (for example, if there exists a record in another table that has a FK related to this detail row, the user should not be allowed to delete this repeat group).

If this was just a list, I know I could use the 'candeleterow' list plugin to make this check inside a php evaluation, but how can I do that for the rows of repeated groups too? It could be nice to have a 'candeleterepeatedgroups' form plugin...
 
To make a sort of 'candeleterepeatedgroups' validation check I thought of this: in the form with repeated groups I could use a PHP form plugin related to the event "onBeforeProcess". Then, in the PHP code field I would make something like that (for now is only a draft-pseudo-php-code):

PHP:
$deletedRowsArray = $formModel->getDeletedRepeatedGroups();

$allowDelete = true;
foreach ($deletedRowsArray as $deletedRow)
{
    if (...conditionToAllowDelete... is false)
    {
        $allowDelete = false;
        break;
    }
}

if ($allowDelete == false)
{
    $formModel->errors['table___field'][] = "error";
    $formModel->getForm()->error = "I'm sorry, there is some sub-row that you cannot delete because actually it's related to another record.";
    return false;
}

return true;

I think this could work, but I don't think there is a 'getDeletedRepeatedGroups()' function... It should return an array of repeated groups that the user would like to delete (those removed from the form, by using the '(-)' button). How can I make that?
 
I think you can compare the original form data and the submitted data to see which (or if any) group was deleted.
 
I think you can compare the original form data and the submitted data to see which (or if any) group was deleted.
Yes, I found that to get the original form data I can use:

PHP:
$origGroupRows = $formModel->getOrigData();

That will return an array with all the records of the group (included those removed by the user with the '(-)' button). Now I have to find how to get the "not deleted" rows from the repeated groups and then compare the two arrays to get just the rows of the deleted ones...
 
I have to test it properly but I think I found the solution:

PHP:
$groupId = ...; // <-- this is the ID of the group related to the joined records (repeated group) for which you want to check some conditions on delete
$repeatedGroupObj = ($formModel->getGroups())[$groupId];
$origGroupRowsIds = $repeatedGroupObj->getOrigGroupRowsIds();
$removedRowsIds = array_diff($origGroupRowsIds, $data['detailTable___fieldID']);

foreach ($removedRowsIds as $removedRowId)
{
    if (...conditionToAllowDelete... is false)
    {
        // condition failed on some detail record, so we stop the form submission:
        $formModel->errors['table___someFieldToInvalidate'][] = "error";
        $formModel->getForm()->error = "I'm sorry, there is some sub-row that you cannot delete because actually it's related to another record.";
        return false;
    }
}

return true;
 
Last edited:
After some tests I can say that the above solution works quite well but it's not perfect...

After the processing of the above PHP script, if there is some removed repeated group that doesn't satisfy some 'conditionToAllowDelete', the form submission will stop and the user will see my error message... That's ok, it's what I wanted, but the problem now is that the removed groups are no longer in the form page, so the user has no way to 'correct' the situation and resubmit the form without first manually reload the page... That's not very nice... Is there some way to make the above php code redisplay the removed groups to let the user correct the situation without having to reload the page?
 
Will not it be easier to disable the deletion of groups, that should not be deleted, with javascript?
Easier? I don't know... How you check in javascript what are the groups that could be deleted? In PHP, for each detail row the user wants to delete, I do a query on a related database table to check if it has records that point to the detail row the user would like to delete. If there aren't related records, then the validation is ok and the detail row could be deleted.
 
but the problem now is that the removed groups are no longer in the form page
Hmm, yes, a failed validation keeps the edited values (which makes sense in any other case then this).

I would try with a custom template. In default_repeatgroup.php you have
Code:
  ..
foreach ($group->subgroups as $subgroup) :
...
      // Add the add/remove repeat group buttons
        if ($group->editable && ($group->canAddRepeat || $group->canDeleteRepeat)) : ?>
            <div class="fabrikGroupRepeater pull-right btn-group">
                <?php if ($group->canAddRepeat) :
                    echo $this->addRepeatGroupButton;
                endif;
                if ($group->canDeleteRepeat) :
                    echo $this->removeRepeatGroupButton;
                endif;?>
            </div>
I think you can include your condition here somewhere to set $group->canDeleteRepeat = false;
 
I just guessed.
I did it this way: when I click on the group deletion button, with ajax query I do a check in the database. If there are any records - a alert message comes out. if no records are deleted, the group is deleted. Particularly, delete event should first be removed.
So thinking about is not much easier, but it will bring the desired result.
 
Hmm, yes, a failed validation keeps the edited values (which makes sense in any other case then this).

I would try with a custom template. In default_repeatgroup.php you have
Code:
  ..
foreach ($group->subgroups as $subgroup) :
...
      // Add the add/remove repeat group buttons
        if ($group->editable && ($group->canAddRepeat || $group->canDeleteRepeat)) : ?>
            <div class="fabrikGroupRepeater pull-right btn-group">
                <?php if ($group->canAddRepeat) :
                    echo $this->addRepeatGroupButton;
                endif;
                if ($group->canDeleteRepeat) :
                    echo $this->removeRepeatGroupButton;
                endif;?>
            </div>
I think you can include your condition here somewhere to set $group->canDeleteRepeat = false;
Thanks for the suggestion, I think it could work very well! But in this way I should create a new form template for each form where I have a master-detail relationship with repeated groups? That could be a little cumbersome... I would prefer a solution where I can manage all the logic (as much as possible) in the Fabrik backend.

For now I adopted a very basic but fast and functional solution: in the returned error message that is displayed after an invalid form submit, I insert a simple invitation (with a link) for the user to go back to the previous page:

PHP:
$formModel->getForm()->error = "I'm sorry, there is some sub-row that you cannot delete because actually it's related to another record. Please <a href='javascript:history.go(-1)' title='Return to the previous page'>CLICK HERE TO GO BACK</a> and try again.";

In fact, when you go back to the previous page, you will have all the repeated groups re-rendered by the browser, so the user can try again to make its edit and resubmit it.
 
I just guessed.
I did it this way: when I click on the group deletion button, with ajax query I do a check in the database. If there are any records - a alert message comes out. if no records are deleted, the group is deleted. Particularly, delete event should first be removed.
So thinking about is not much easier, but it will bring the desired result.
This could be very cumbersome to make... Have you already implemented such a thing?
I think that until there is a specific plugin to do this, the template solution suggested by troaster is the way to go if you want to hide the '(-)' button for detail rows that should not be allowed to be deleted.
 
UPDATE: I made some tests and unfortunately the approach of go back of one page within the browser doesn't work... When you go back to the previous page, the browser will render again the removed groups too, and this is good, but then, if you make another submit, the php script will behave as if it had received the previous form data instead of the new.

But don't worry! I have a solution... To make it work without problems, instead of let your browser go back of one page, you can just make the browser reload the current page in this way:

PHP:
$formModel->getForm()->error = "I'm sorry, there is some sub-row that you cannot delete because actually it's related to another record. Please <a href='{$_SERVER->HTTP_REFERER}' title='Return to the previous page'>CLICK HERE</a> and try again.";

Now the submit of the reloaded page will work correctly. :)
 
We are in need of some funding.
More details.

Thank you.

Members online

Back
Top