JavaScript TypeError:无法读取未定义的属性“ id”

时间:2018-12-13 18:11:13

标签: javascript jquery html delete-row uncaught-typeerror

我有一个HTML表,用户可以在其中填写他们拥有帐户的社交网络的名称和URL。每行都有一个复选框。在jQuery和JavaScript的帮助下,按添加行按钮时,将动态地将一行添加到表中,而按删除行按钮则删除了选中了复选框的行。

删除选定的行后,我想id分配给其余各行的元素和复选框以串行方式,以便这些行始终是连续的。

由于childNodes[]似乎没有导致元素不可用,所以我找不到导致它引发错误的原因。请帮忙!

    // variable to keep track of rows(records)
    var social_recs_num = 1;
    $(document).ready(function () {
    
      $("#social_add_rec").click(function () {
    
        social_recs_num++;
        var markup = "<tr> <th scope=\"row\"> <div class=\"form-group\"> <div class=\"form-check\"> <input type=\"checkbox\" class=\"form-check-input\" id=\"social_rec" + social_recs_num + "\" name=\"social_rec\"> <label class=\"form-check-label\" for=\"social_rec" + social_recs_num + "\"> " + social_recs_num + "</label> </div></div></th> <td> <div class=\"form-group shadow-sm\"> <label for=\"name_social" + social_recs_num + "\">Select or Type</label> <input type=\"text\" list=\"name_social" + social_recs_num + "\" class=\"form-control\" placeholder=\"Name\"> <datalist id=\"name_social" + social_recs_num + "\"> <option value=\"Wikipedia\">Wikipedia</option> <option value=\"Youtube\">Youtube</option> <option value=\"Facebook\">Facebook</option> <option value=\"Twitter\">Twitter</option> <option value=\"Pinterest\">Pinterest</option> </datalist> </div></td><td> <div class=\"form-group shadow-sm\"> <textarea class=\"form-control\" id=\"url_social" + social_recs_num + "\" cols=\"30\" rows=\"1\" placeholder=\"URL\"></textarea> </div></td></tr>"; //in case of id we need to do it like: "min_sysreq" +social_recs_num...as social_recs_num has been incremented priorly it will be the row number of row to be added
    
        $("table tbody").append(markup);
    
      });
    
      // Find and remove selected table rows...only condition is that there must be present attribute name='sysreq_rec' in input element for checkbox of every row
    
      $("#social_delete_rec").click(function () {
    
        $("table tbody").find('input[name="social_rec"]').each(function () {
    
          if ($(this).is(":checked")) {
            social_recs_num = social_recs_num - $(this).length;
            $(this).parents("tr").remove();
    
          }
    
        });
        // to be run when a row is deleted...this assigns ids to input elements in serial manner            
        var table = document.getElementById("mytab1");
        var rowCount = table.rows.length;
        
        // i has been initiated with 1, as header row is the 0th row
        for (var i = 1; i < rowCount; i++) {
          var row = table.rows[i];
    
          // on this line, getting error: `Uncaught TypeError: Cannot read property 'id' of undefined`
          row.childNodes[0].childNodes[0].childNodes[0].childNodes[0].id = "social_rec" + i;
          row.childNodes[0].childNodes[0].childNodes[0].childNodes[1].for = "social_rec" + i;
          row.childNodes[0].childNodes[0].childNodes[0].childNodes[1].innerHTML = " " + i;
    
          row.childNodes[1].childNodes[0].childNodes[0].for = "name_social" + i;
          row.childNodes[1].childNodes[0].childNodes[1].list = "name_social" + i;
          row.childNodes[1].childNodes[0].childNodes[2].id = "name_social" + i;
    
          row.childNodes[2].childNodes[0].childNodes[0].id = "url_social" + i;
    
          //iterate through rows
          //rows would be accessed using the "row" variable assigned in the for loop
    
        }
    
      });
    
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table table-bordered" id="mytab1">
      <thead>
        <tr>
          <th scope="col">
            #
          </th>
          <th scope="col">
            Name
          </th>
          <th scope="col">
            URL
          </th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th scope="row">
            <div class="form-group">
              <div class="form-check">
                <input type="checkbox" class="form-check-input" id="social_rec1" name="social_rec">
                <label class="form-check-label" for="social_rec1"> 1</label>
              </div>
            </div>
          </th>
          <td>
            <div class="form-group shadow-sm">
              <label for="name_social1">Select or Type</label>
              <input type="text" list="name_social1" class="form-control" placeholder="Name">
              <datalist id="name_social1">
                <option value="Wikipedia">Wikipedia</option>
                <option value="Youtube">Youtube</option>
                <option value="Facebook">Facebook</option>
                <option value="Twitter">Twitter</option>
                <option value="Pinterest">Pinterest</option>
              </datalist>
            </div>
          </td>
          <td>
            <div class="form-group shadow-sm">
              <textarea class="form-control" id="url_social1" cols="30" rows="1" placeholder="URL"></textarea>
            </div>
          </td>
        </tr>
      </tbody>
    </table>
    <button class="btn btn-primary" type="button" id="social_add_rec">Add Row</button>
    <button class="btn btn-primary" type="button" id="social_delete_rec">Delete Row</button>

P.S。 1.我使用过jQuery和Bootstrap。 2. this问题似乎很接近,但是我认为我没有相同的错误。

编辑:

我需要按用户显示(或存储)输入,为此我编写了以下JavaScript代码。

var social = function () {

    var val = "social:\n";
    for (x = 1; x <= social_recs_num; x++) {
      //where social_recs_num is number of rows
      val = val + "\s\s-\n";
      val = val + "\s\s\s\s" + "name: " + getElementById("name_social" + x) + "\n";
      val = val + "\s\s\s\s" + "url: " + getElementById("url_social" + x) + "\n";
    }

    return val;

}

函数social返回用户以YAML格式输入的值。对于此代码,

  

删除选定的行时,我想以串行方式将id分配给其余每行的输入元素和复选框

1 个答案:

答案 0 :(得分:0)

问题:

您看到的问题是因为您试图获取html元素的'childNodes'属性。为了访问该属性,您必须通过在元素周围添加'$()'将元素强制转换为jQuery对象。在这种情况下,它将是“ $(row)”。

但是,如果使用代码执行此操作,则由于嵌套的.childNodes [0]的混乱,您仍然会出错。您可以使用现有代码来使它正常工作,但是...

建议的重构:

...正如其他人所述,有更优雅的方法来解决此问题。您可以通过多种方法来解决它,但是鉴于您当前使用的html,我将重构为以下内容:

//...


// to be run when a row is deleted...this assigns ids to input elements in serial manner                
$('#mytab1 tbody tr').each(function() {
    var rowNum = $(this)[0].rowIndex;

    var formcheck = $(this).find('.form-check');  
    formcheck.find('.form-check-input')[0].id = 'social_rec' + rowNum;
    formcheck.find('.form-check-label')[0].for = 'social_rec' + rowNum;
    formcheck.find('.form-check-label')[0].innerHTML = ' ' + rowNum;

    var formName = $(this).find('td')[0];
    $(formName).find('label')[0].for = 'social_rec' + rowNum;
    $(formName).find('input')[0].list = 'social_rec' + rowNum;
    $(formName).find('datalist')[0].id = 'social_rec' + rowNum;

    var formUrl = $(this).find('td')[1];
    $(formUrl).find('textarea')[0].id = 'social_rec' + rowNum;          
});


//...

这将用jquery .each循环替换for循环,然后使用.find()函数循环播放要操作的每个控件。您还将注意到,它使用rowIndex()函数来确定分配行的编号。

我认为使用这种方法的好处是,读取代码和确定受影响的控件要容易得多。您还可以另外重构HTML,以使用要定位的控件所特有的类,然后可以使用类选择器更改这些控件。

希望有帮助!