jQuery обработчик кликов всегда захватывает кнопку в первой доступной строке таблицы, а не ту, которая была нажата - PullRequest
0 голосов
/ 05 марта 2020

Я использую библиотеку jQuery, написанную кем-то другим (Bootstable. js). Так как он только обновляет html, мне нужно создать собственную функцию Ajax для отправки информации в базу данных, один из этих элементов является идентификатором (который является первым столбцом каждой строки). Каждый раз, когда я обновляю таблицу, она захватывает только первую строку из доступных (ID = 4). Как я могу получить доступ к правильной кнопке?

Вот моя страница:

//Init the array
var array = [];

document.title = 'Public IPs';

$(function() {
  /*
  Init the dialogs
   */
  $('#table_edit_dialog').dialog({
    autoOpen: false,
    modal: true,
    show: 'blind',
    hide: 'fade',
    resizable: false,
    draggable: false,
    close: function() {
      location.reload();
    }
  });
  $('#confirm_table_edit_dialog').dialog({
    autoOpen: false,
    modal: true,
    show: 'blind',
    hide: 'fade',
    resizable: false,
    draggable: false,
    buttons: {
      "Confirm": function() {
        updateTable();
        $(this).dialog('close');
      },
      "Cancel": function() {
        $(this).dialog('close');
        location.reload();
        console.log('Clicked Cancel button');
      }
    }
  });
  //Initalize the table
  initTable();

  //Click handler for edit accept button
  $('#bAcep').on('click', function() {
    console.log('Clicked bAcep button');
    //Get the <td> elements that are not the first or last (id and button)
    let text = $(this).parent().parent().parent().find('td:gt(0):lt(6)');
    //Get the id text in the first <td> element. To be used in the php script
    let id = $(this).parent().parent().parent().find('td:eq(0)').text();
    //For debugging
    console.log('ID of row: ' + id);
    //Push the ID to the array to send to php
    array.push(id);
    //Push the rest to the array
    text.each(function() {
      array.push($(this).text());
    });
    //Open the confirm dialog
    $('#confirm_table_edit_dialog').dialog('open');
  });
  //Reload the page on Cancel button click
  $('#bCanc').on('click', function() {
    console.log('Clicked bCanc button');
    location.reload();
  })
});

function initTable() {
  //Make the table editable
  $('#editable_table').SetEditable({
    //Don't allow editing of ID,IP Address, or Vendor column
    columnsEd: "3,4,5,6",
    onEdit: function(row) {
      console.log('Called onEdit');
      $('#bAcep').trigger('click');
    }
  });
  //Remove the delete button from each row
  //It will not be used. All deletions will be handled via database.
  $('td').each(function() {
    $('#bElim').remove();
  });
  //Add noShowButton class to every row greater than the first and less than the 3rd
  //These will always be static entries
  $('tr:gt(0):lt(3)').addClass('noShowButton');
  //Remove the edit button
  $('.noShowButton').find('.btn').remove();
}

function updateTable() {
  console.log('Called updateTable function');
  $.ajax({
    type: 'post',
    url: 'includes/edit_IP_table.php',
    data: {
      array: array
    },
    dataType: 'json',
    success: function(data) {
      console.log(data);

      //Show all the updated info in a dialog
      let valid_ip = '<h3>Updated IP Table:</h3>' +
        '<p><strong>Row ID: </strong>' + data.id + '</p>' +
        '<p><strong>IP: </strong>' + data.ip + '</p>' +
        '<p><strong>Vendor: </strong>' + data.vendor + '</p>' +
        '<p><strong>Assigned To: </strong>' + data.assigned_to + '</p>' +
        '<p><strong>Policy: </strong>' + data.policy + '</p>' +
        '<p><strong>DNS: </strong>' + data.dns + '</p>' +
        '<p><strong>Other Info: </strong>' + data.other_info + '</p>';
      $('#table_edit_dialog').html(valid_ip);
      $('#table_edit_dialog').dialog('open');
      //Clear out the array
      array = [];
      console.log('Emptied array: ' + array);

    },
    error: function(jqXHR, status, error) {
      console.log(error);
      array = [];
      console.log('Emptied array: ' + array);
    }
  })
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<table id="editable_table" class="table table-bordered">
  <thead>
    <tr>
      <th>ID</th>
      <th>IP Address</th>
      <th>Vendor</th>
      <th>Assigned To</th>
      <th>Firewall Policies</th>
      <th>DNS Records</th>
      <th>Other Info</th>
      <th>Edit</th>
      <th name="buttons"></th>
    </tr>
  </thead>
  <tbody>
    <tr id="1" class="noShowButton">
      <td>1</td>
      <td>123.456.789.10</td>
      <td>AT&amp;T</td>
      <td>router</td>
      <td></td>
      <td></td>
      <td></td>
      <td name="buttons">
        <div class="btn-group pull-right"></div>
      </td>
    </tr>
    <tr id="2" class="noShowButton">
      <td>2</td>
      <td>123.456.789.10</td>
      <td>AT&amp;T</td>
      <td>some web site</td>
      <td></td>
      <td></td>
      <td></td>
      <td name="buttons">
        <div class="btn-group pull-right"></div>
      </td>
    </tr>
    <tr id="3" class="noShowButton">
      <td>3</td>
      <td>123.456.789.10</td>
      <td>AT&amp;T</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td name="buttons">
        <div class="btn-group pull-right"></div>
      </td>
    </tr>
    <tr id="4">
      <td>4</td>
      <td>123.456.789.102</td>
      <td>AT&amp;T</td>
      <td>asdfasdfdsaf</td>
      <td>asdfsdfadsf</td>
      <td>some DNS stuff</td>
      <td>hello!!</td>
      <td name="buttons">
        <div class="btn-group pull-right"><button id="bEdit" type="button" class="btn btn-sm btn-default" onclick="rowEdit(this);"><span class="glyphicon glyphicon-pencil"> </span></button><button id="bAcep" type="button" class="btn btn-sm btn-default" style="display:none;" onclick="rowAcep(this);"><span class="glyphicon glyphicon-ok"> </span></button>
          <button
            id="bCanc" type="button" class="btn btn-sm btn-default" style="display:none;" onclick="rowCancel(this);"><span class="glyphicon glyphicon-remove"> </span></button>
        </div>
      </td>
    </tr>
    <tr id="5">
      <td>5</td>
      <td>123.456.789.10</td>
      <td>AT&amp;T</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td name="buttons">
        <div class="btn-group pull-right"><button id="bEdit" type="button" class="btn btn-sm btn-default" onclick="rowEdit(this);"><span class="glyphicon glyphicon-pencil"> </span></button><button id="bAcep" type="button" class="btn btn-sm btn-default" style="display:none;" onclick="rowAcep(this);"><span class="glyphicon glyphicon-ok"> </span></button>
          <button
            id="bCanc" type="button" class="btn btn-sm btn-default" style="display:none;" onclick="rowCancel(this);"><span class="glyphicon glyphicon-remove"> </span></button>
        </div>
      </td>
    </tr>
    <tr id="">
      <td>6</td>
      <td>123.456.789.10</td>
      <td>AT&amp;T</td>
      <td></td>
      <td>asdfasdfasdf</td>
      <td></td>
      <td></td>
      <td name="buttons">
        <div class="btn-group pull-right"><button id="bEdit" type="button" class="btn btn-sm btn-default" onclick="rowEdit(this);" style=""><span class="glyphicon glyphicon-pencil"> </span></button><button id="bAcep" type="button" class="btn btn-sm btn-default accept" style="display: none;"
            onclick="rowAcep(this);"><span class="glyphicon glyphicon-ok"> </span></button><button id="bCanc" type="button" class="btn btn-sm btn-default" style="display: none;" onclick="rowCancel(this);"><span class="glyphicon glyphicon-remove"> </span></button></div>
      </td>
    </tr>
  </tbody>
</table>

Вот библиотека. Я пропустил функции rowElim(), rowAddNew() и TableToCSV(), поскольку не буду их использовать. Я также перевел комментарии на английский язык sh, так как все они были написаны на испанском sh, чтобы помочь их понять.

/*
Bootstable
 @description  Javascript library to make HMTL tables editable, using Bootstrap
 @version 1.1
 @autor Tito Hinostroza
*/
"use strict";
//Global variables
var params = null;          //Parameters
var colsEdi =null;
var newColHtml = '<div class="btn-group pull-right">'+
    '<button id="bEdit" type="button" class="btn btn-sm btn-default" onclick="rowEdit(this);">' +
    '<span class="glyphicon glyphicon-pencil" > </span>'+
    '</button>'+
    '<button id="bElim" type="button" class="btn btn-sm btn-default" onclick="rowElim(this);">' +
    '<span class="glyphicon glyphicon-trash" > </span>'+
    '</button>'+
    '<button id="bAcep" type="button" class="btn btn-sm btn-default" style="display:none;" onclick="rowAcep(this);">' +
    '<span class="glyphicon glyphicon-ok" > </span>'+
    '</button>'+
    '<button id="bCanc" type="button" class="btn btn-sm btn-default" style="display:none;" onclick="rowCancel(this);">' +
    '<span class="glyphicon glyphicon-remove" > </span>'+
    '</button>'+
    '</div>';
var colEdicHtml = '<td name="buttons">'+newColHtml+'</td>';

$.fn.SetEditable = function (options) {
    var defaults = {
        columnsEd: null,         //Index to editable columns. If null all td editables. Ex.: "1,2,3,4,5"
        $addButton: null,        //Jquery object of "Add" button
        onEdit: function() {}   //Called after edition
        //onBeforeDelete: function() {}, //Called before deletion -- NOT USED
        //onDelete: function() {}, //Called after deletion -- NOT USED
        //onAdd: function() {}     //Called when added a new row -- NOT USED
    };
    params = $.extend(defaults, options);
    this.find('thead tr').append('<th name="buttons"></th>');  //encabezado vacío
    this.find('tbody tr').append(colEdicHtml);
    var $tabedi = this;   //Read reference to the current table, to resolve "this" here.
    //Process "addButton" parameter
    if (params.$addButton != null) {
        //Se proporcionó parámetro -- Parameter provided
        params.$addButton.click(function() {
            rowAddNew($tabedi.attr("id"));
        });
    }
    //Process "columnsEd" parameter
    if (params.columnsEd != null) {
        //Extract felds
        colsEdi = params.columnsEd.split(',');
    }
};
function IterarCamposEdit($cols, tarea) {
//Itera por los campos editables de una fila -- Go through the editable fields of a row
    var n = 0;
    $cols.each(function() {
        n++;
        if ($(this).attr('name')=='buttons') return;  //excluye columna de botones -- excludes button column
        if (!EsEditable(n-1)) return;   //noe s campo editable -- no editable field
        tarea($(this));
    });

    function EsEditable(idx) {
        //Indica si la columna pasada está configurada para ser editable -- Indicates if the last column is set to be editable
        if (colsEdi==null) {  //no se definió -- it was not defined
            return true;  //todas son editable -- all are editable
        } else {  //hay filtro de campos -- there is field filter
            for (var i = 0; i < colsEdi.length; i++) {
                if (idx == colsEdi[i]) return true;
            }
            return false;  //no se encontró -- it was not found
        }
    }
}
function FijModoNormal(but) {
    $(but).parent().find('#bAcep').hide();
    $(but).parent().find('#bCanc').hide();
    $(but).parent().find('#bEdit').show();
    $(but).parent().find('#bElim').show();
    var $row = $(but).parents('tr');  //accede a la fila -- access the row
    $row.attr('id', '');  //quita marca -- remove mark
}
function FijModoEdit(but) {
    $(but).parent().find('#bAcep').show();
    $(but).parent().find('#bCanc').show();
    $(but).parent().find('#bEdit').hide();
    $(but).parent().find('#bElim').hide();
    var $row = $(but).parents('tr');  //accede a la fila -- access the row
    $row.attr('id', 'editing');  //indica que está en edición -- indicates that it is in edicion
}
function ModoEdicion($row) {
    if ($row.attr('id')==='editing') {
        console.log('Entered Edit Mode'); //Added by CS
        return true;
    } else {
        console.log('Exited Edit Mode'); //Added by CS
        return false;
    }
}
function rowAcep(but) {
    console.log('Called rowAcep function');
    //Acepta los cambios de la edición -- Accept the changes of the edition
    var $row = $(but).parents('tr');  //accede a la fila -- access the row
    var $cols = $row.find('td');  //lee campos -- read fields
    if (!ModoEdicion($row)) return;  //Ya está en edición -- Is already in edition
    //Está en edición. Hay que finalizar la edición -- It is in edition. You have to finish the edition
    IterarCamposEdit($cols, function($td) {  //itera por la columnas --iterate through the columns
        var cont = $td.find('input').val(); //lee contenido del input -- read input content
        $td.html(cont);  //fija contenido y elimina controles -- set content and remove controls
    });
    FijModoNormal(but);
    params.onEdit($row);
}
function rowCancel(but) {
//Rechaza los cambios de la edición -- Repeat the changes of the edition
    var $row = $(but).parents('tr');  //accede a la fila -- access the row
    var $cols = $row.find('td');  //lee campos read fields
    if (!ModoEdicion($row)) return;  //Ya está en edición -- It is already in edition
    //Está en edición. Hay que finalizar la edición -- It is in edition. You have to finalize the edition
    IterarCamposEdit($cols, function($td) {  //itera por la columnas -- iterate through the columns
        var cont = $td.find('div').html(); //lee contenido del div -- read div content
        $td.html(cont);  //fija contenido y elimina controles -- set content and remove controls
    });
    FijModoNormal(but);
}
function rowEdit(but) {  //Inicia la edición de una fila -- Start editing a row
    var $row = $(but).parents('tr');  //accede a la fila -- access the row
    var $cols = $row.find('td');  //lee campos -- read fields
    if (ModoEdicion($row)) return;  //Ya está en edición -- It is already in edition
    //Pone en modo de edición -- It puts in edit mode
    IterarCamposEdit($cols, function($td) {  //itera por la columnas -- iterate through the columns
        var cont = $td.html(); //lee contenido -- read content
        var div = '<div style="display: none;">' + cont + '</div>';  //guarda contenido -- keep content
        var input = '<input class="form-control input-sm"  value="' + cont + '">';
        $td.html(div + input);  //fija contenido -- set content
    });
    FijModoEdit(but);
}

Я попытался получить доступ к кнопке, выбрав кнопку #bAcep, которая был не style="display:none", но он по-прежнему захватывает первый:

$('#bAcep').on('click', function () {
            console.log('Clicked bAcep button');
            //Get the <td> elements that are not the first or last (id and button)
            let text = $(this).parent().parent().parent().find('td:gt(0):lt(6)');
            //Get the first button that is not display:none
            let visible_btn = $('#bAcep:not([style="display:none"]):first');
            //Get the id text in the first <td> element. To be used in the php script
            //let id = $(this).parent().parent().parent().find('td:eq(0)').text();
            let id = visible_btn.parent().parent().parent().find('td:eq(0)').text();
            //For debugging
            console.log('ID of row: ' + id);
            //Push the ID to the array to send to php
            array.push(id);
            //Push the rest to the array
            text.each(function () {
                array.push($(this).text());
            });
            //Open the confirm dialog
            $('#confirm_table_edit_dialog').dialog('open');
        });

Мой вывод консоли показывает:

Clicked bAcep button
ID of row: 4

Вот скриншот таблицы :

Table Screenshot

Возможно, я что-то упустил в библиотеке?

1 Ответ

0 голосов
/ 05 марта 2020

Я принял совет mplungjan и использовал класс в качестве идентификатора для кнопки. Я все еще использую прослушиватель щелчков по идентификатору, но нахожу его по классу внутри функции, например:

Сначала, в коде библиотеки, я подключился к вызову функции rowAcep и добавил класс , accept:

function rowAcep(but) {
    $(but).addClass('accept'); //<-- ADDED CLASS HERE
    //Acepta los cambios de la edición -- Accept the changes of the edition
    var $row = $(but).parents('tr');  //accede a la fila -- access the row
    var $cols = $row.find('td');  //lee campos -- read fields
    if (!ModoEdicion($row)) return;  //Ya está en edición -- Is already in edition
    //Está en edición. Hay que finalizar la edición -- It is in edition. You have to finish the edition
    IterarCamposEdit($cols, function($td) {  //itera por la columnas --iterate through the columns
        var cont = $td.find('input').val(); //lee contenido del input -- read input content
        $td.html(cont);  //fija contenido y elimina controles -- set content and remove controls
    });
    FijModoNormal(but);
    params.onEdit($row);
}

Тогда мой код:

//Click handler for edit accept button
$('#bAcep').on('click', function () {
    console.log('Clicked bAcep button');
    //Get the <td> elements that are not the first or last (id and button)
    let text = $('.accept').closest('tr').find('td:gt(0):lt(6)'); //<-- New Code Here

    //Get the id text in the first <td> element. To be used in the php script
    let id = $('.accept').closest('tr').find('td:eq(0)').text(); //<-- And here

    //Rest of code here
});

Итак, это действительно была проблема с дублирующимся идентификатором. Я думаю, плохой дизайн с библиотекой, но это работает сейчас!

...