Deletion of Drupal table rows via an Ajax call was never too difficult. You just add a controller callback:

organization.person.delete:
  path: '/person/{person_id}/delete'
  defaults:
    _title: 'Delete Person'
    _controller: '\Drupal\organization\Form\Person\PersonList::deletePerson'
  requirements:
    _role: 'editor'

Provide the corresponding implementation in a php file for the deletion logic:

public function deletePerson(Request $request) {
	$person_id = \Drupal::routeMatch()->getParameter('person_id');
	
	\Drupal::database()
		->delete('person')
		->condition('person_id', $person_id)
		->execute();

	$response = new AjaxResponse();

	return ($response);
}

And finally provide an operation on the table row to invoke the callback:

$operations['delete'] = [
	'#type' => 'link',
	'#title' => t('Delete'),
	'#weight' => 5,
	'#url' => Url::fromRoute('organization.person.delete', array('person_id' => $row->person_id)),
	'#attributes' => [
	   'class' => ['use-ajax'],
	],
];

(ensure to provide the ‘use-ajax’ class on the operation to enable Drupal to automatically use Ajax).

The missing piece in the puzzle was removing the row from the table client side after the Ajax operation succeeded. With the various commands available for AjaxResponse beginning Drupal 8.0.x, the same is a breeze now:

public function deletePerson(Request $request) {
	$person_id = \Drupal::routeMatch()->getParameter('person_id');
	
	\Drupal::database()
		->delete('person')
		->condition('person_id', $person_id)
		->execute();

	$response = new AjaxResponse();

	$response->addCommand(new MessageCommand(t('Person deleted successfully.'), '.person-list-status-wrapper'));
	$response->addCommand(new InvokeCommand('.person-row-' . $person_id, 'remove'));
	
	return ($response);
}

We use Drupal’s InvokeCommand passing it a css class, and the method as remove. From Drupal’s docs:

The ‘invoke’ command will instruct the client to invoke the given jQuery method with the supplied arguments on the elements matched by the given selector.

So yeah, your specific table row (with the css class specified) disappears when the Ajax operation completes. But wait; doesn’t this mean each table row needs to have a specific class so only a single row gets removed from the table and not all.

Yeah, you got it right buddy. Each table row needs to have a unique class for this to work. And the same has been outlined in my previous blog post: “Drupal – adding row specific css class when preparing a table“.

Take a look there for adding a row specific class and then the code in this post would help you delete the row server-side and eliminate it from the table client-side once the operation completes.

Still have a question, feel free to ask in the comments below.