Delete order's details' line without changing page using AJAX Following a teacher's JavaScript code I intend to delete order's lines with AJAX.

I have tried the code below and it allows the user to delete line by line but for example for the last line it won't delete it.

Function to display order's details:

    public static function showOrderDetails($id){
    $res=DB::execute_sql('select id,idbebida, unidades, pvp from lineaspedido where idpedido=?', array($id));

    if($res){
        $res -&gt; setFetchMode(PDO::FETCH_NAMED);
        $first=true;
        echo '&lt;table class="center"&gt;&lt;tr&gt;';
        foreach ($res as $table_row) {
            if($first){ //HEADERS

                foreach ($table_row as $row_index =&gt; $row_data) { // titulos campos
                    if($first){ //TO NOT DISPLAY ID
                        $first=false;
                        continue;
                    }
                    echo "&lt;th&gt;$row_index&lt;/th&gt;";
                }

            }
            echo '&lt;/tr&gt;';


            $first=true;
            foreach ($table_row as $row_data) { // DATA
                if ($first){
                    $idLinea=$row_data;
                    $first=false;
                    echo "&lt;tr id=\"fila$idLinea\"&gt;";
                } else{
                    echo "&lt;td&gt;$row_data&lt;/td&gt;";
                }
            }

            echo "&lt;td&gt;&lt;button onclick=\"deleteLineaPedido($idLinea )\"&gt;Borrar&lt;/button&gt;&lt;/td&gt;";
           echo "&lt;/tr&gt;";
        }
        echo '&lt;/table&gt;';
    }
}


PHP OBJECT to manage JSON:

    &lt;?php
$res = new stdClass();
$res-&gt;deleted=false; //Attribute DELETED default false
$res-&gt;message=''; //Error message
try{
    $datoscrudos = file_get_contents("php://input"); //READ
    $datos = json_decode($datoscrudos);
    $db = new PDO("sqlite:./datos.db");
    $db-&gt;exec('PRAGMA foreign_keys = ON;'); //KEYS
    $sql=$db-&gt;prepare('delete FROM lineaspedido WHERE idpedido=?;'); 
    if($sql){
        $sql-&gt;execute(array($datos-&gt;id));
        if($sql-&gt;rowCount()&gt;0){ //NUMBER OF ROWS AFFECTED
           $res-&gt;deleted=true; //WHATEVER have been deleted is refreshed
        }
    }
}catch(Exception $e){
   $res-&gt;message=$e-&gt;getMessage();

header('Content-type: application/json');
echo json_encode($res);


JS function to delete:

function deleteLineaPedido(idLinea){
if(!confirm("Desea borrar la linea de pedido: '"+idLinea+"'")){
    return;
}
var ajax= new XMLHttpRequest();
ajax.onreadystatechange=function(){
    if(this.readyState == 4 &amp;&amp; this.status == 200) {
        var res= JSON.parse(this.responseText); //RESULT in JSON 
        if(res.deleted === true){
            var fila=document.querySelector('#fila'+idLinea); //We choose the first and unique row which has whatever ID needed.
            fila.parentNode.removeChild(fila); //We delete the previous row firstly going to its parent node and then deattaching it.
        }
    }
};
ajax.open("post","borrar_linea_Pedido.php",true);
ajax.setRequestHeader("Content-Type","application/json;charset=UTF-8");
ajax.send(JSON.stringify({"id":idLinea})); //Formato {id:identificador de registro a borrar}


Is there a simpler way to achieve this?

PD: The table used 'lieanspedidos' has the following structure:

id          Numeric identifier of every row of order's details
idpedido    Numeric order identifier
idbebida    Numeric drink identifier
unidades    How many drinks have been inserted into that order's row.
PVP         Each drink's price per unit.
PHP

Variable names, excess variables, logic

When iterating through the rows in showOrderDetails(), the variable $row_index is slightly misleading because that should contain the column name, not an index (typically an integer value):


foreach ($table_row as $row_index =&gt; $row_data) { // titulos campos



A better name for that key would be something like $column_name:

foreach ($table_row as $column_name =&gt; $column_value) { // titulos campos


But the name $row_index would be appropriate for the key on the outer foreach:

foreach ($res as $row_index =&gt; $table_row) {   


Then instead of creating an extra variable called $first, you could utilize $row_index and $column_name to conditionally display the rows and cells.

The first one:


if($first){ //HEADERS



could then be updated to: 

if($row_index === 0){ //HEADERS


And then the second one, in the nested loop:


if($first){ //TO NOT DISPLAY ID



Could be changed to:

if($column_name === 'id'){ //TO NOT DISPLAY ID


And the second inner loop could be updated as well:


foreach ($table_row as $row_data) { // DATA
      if ($first){
          continue;



Could be rewritten to add the row if the column name is id: 

foreach ($table_row as $column_name =&gt; $column_value) { // DATA
    if ($column_name === 'id'){
        $idLinea=$column_value;


And then $first could be eliminated entirely.

Alternatively, the condition in the first nested loop could be negated and then the continue could be eliminated:

if($column_name !== 'id'){ //DO NOT DISPLAY ID
    echo "&lt;th&gt;$column_name&lt;/th&gt;";
}


See that all together in this playground example (not connected with Javascript/AJAX requests).

JS

The line to look up the element to remove by id attribute:


var fila=document.querySelector('#fila'+idLinea); //We choose the first and unique row which has whatever ID needed.



Could be changed to use document.getElementById()

  var fila=document.getElementById('fila'+idLinea); //We choose the first and unique row which has whatever ID needed.  


There are a few discussions about which to use: 


this Sitepoint forum
this SO question and its answers (and related posts)


The general consensus is that getElementById() is quicker than querySelector(). For a small page like this it would likely not be noticeable.