简体   繁体   中英

jquery Datatables multiple tables populated from partial view - 'Cannot Reinitialize' error

I have an MVC project where I'm using jquery DataTables 1.10.2. Within my project's pages I often have multiple places where I need to reuse a partial view, which contains a self-contained jquery DataTable instance, initialization, and handlers. As the partial view is being built I uniquely name each DT instance using a GUID, including all other buttons, etc, so each should be able to exist in its own world, not caring about those around it. Or so I thought... I've read quite a bit on this issue and I can't seem to determine why this is happening. From what I'm doing I don't believe that I'm attempting to change/reinitialize an existing DT instance. When I only have a single one of these DT partial views everything is great. Any thoughts?

I have 3 of these partial views that must reside on the page, and I always get this kinda message: 重新初始化错误弹出窗口

Also, only the last instance actually shows any records, 3x what it's supposed to display, and all the others are just blank (not even the no data message).

1. Here's how I create my raw HTML table within my partial view , where I have a unique identifier for the table: HTML表格代码

2. Here's an example how the calling view requests the partial view in question : I pass a unique identifier (GUID), along with my data via a ViewModel into the partial view. All standard MVC kinda stuff, and is working fine.

视图调用局部视图的示例

3. Here's my partial view initialization of the DataTable with razor injected into the javascript creating a unique HTML table ID for each DT to use, along with a unique DT global object variable (c@unique), which when populated will look something like this: c6e201ac10b4a4a6a987878c7b2390fa4. I shouldn't need to reinitialize anything, despite DT telling me. Each version of the DataTable partial view should have all its variables (c@unique, rows@unique, etc.) to be unique. The existingData variable is set here, which is passed in via the ViewModel:

json编码数据

        c@(unique) = $('#@(unique)phones').DataTable(
{
    "data" : existingData
, "responsive": true
, "searching" : false        
, "paging": false
, "order": 0
, "createdRow" : function (row, data, index){
    $(row).attr("data-id", index);
    rows@(unique)++;
}
, "columns": [
    { "data": "Id"
       , "visible" : false
    }
  , { "data": "PhoneTypeID", "title": "Phone Type",
      render : function (data, type, row, meta) {
          // Renders combination of select element, with exisitng value correctly selected and validation control
          var $clone = $select.clone();
          $clone.attr('name', 'Phones[' + rows@(unique) + '].PhoneTypeID' ); // changing the phone collection name for serialization
          $clone.find('option[value="' + data + '"]').attr('selected','selected'); // attempting to match existing data

          $clone.attr('data-val', 'true' ); // adding validation
          $clone.attr('data-val-required', 'Phone Type Required' ); // adding error message
          var validation = ' <div><span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows@(unique) + '].PhoneTypeID" data-valmsg-replace="true" </span></div>';

          var selectctl =  $clone.wrap('<div></div>').parent().html();

          // combines both the select control and the validation span element
          return selectctl.concat(validation);
      }}
  , { "data": "PhoneNumber", "title": "Phone Number",
      render : function (data, type, row) {
          // Renders combination of phone number text box, with exisitng value correctly selected and validation control
          var phoneDetail = '<div><input class="form-group" name="Phones[' + rows@(unique) + '].PhoneNumber" placeholder="Number" type="tel" pattern="\d{3}[\-]\d{3}[\-]\d{4}"  value="' + data + '"'
               + ' data-val="true" data-val-required="Phone Required" />'
               + ' <input type="hidden" name="Phones[' + rows@(unique) + '].Id" value="' + row["Id"] + '" />'
               + ' <span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows@(unique) + '].PhoneNumber" data-valmsg-replace="true" /></div>';
          return phoneDetail;
      }}
  , { "data" : "Id",
      render :  function (data,type,row,meta){
          var deleteBtn = '<a class="btn btn-warning removeSelected" href="#">Delete</a>';
          return deleteBtn;
      }
  }
]
});

I'm rendering some columns to have a select element (PhoneTypeId), a text box (PhoneNumber) and a button for deleting. The select element is setup using some code that creates a $select element (not included here) that's then cloned within the rendering column to match any existing data. All my element names use this notation (SomeName[index].PropertyName) so the serializer will understand when the page is posted to my collections, etc.

Here's a working example of what it looks like , including when the row is selected and displays the delete button. Not fully styled yet, as I can't seem to have more than 1 on a page! Any help is appreciated!

工作样本

The code itself wasn't the problem. To keep my doc.ready event clean and tidy I used a call to the method LoadDataTable() . When two or more of these partial views were loaded and doc.ready was finally called, there were multiple LoadDataTable methods, each pointing to an already existing instance of a DataTable. This is why I kept getting that initialize error. My Solution: Either create a dynamically named LoadDataTable method (using razor), or just put everything directly inside the partial's doc.ready method. Working fine now!

What I could see is that you weren't trying to destroy an existing table. Looking at the following in your post:

c@(unique) = $('#@(unique)phones').DataTable(
{
    "data" : existingData
, "responsive": true
, "searching" : false        
, "paging": false
, "order": 0
, "createdRow" : function (row, data, index){
    $(row).attr("data-id", index);
    rows@(unique)++;
}
, "columns": [
    { "data": "Id"
       , "visible" : false
    }
  , { "data": "PhoneTypeID", "title": "Phone Type",
      render : function (data, type, row, meta) {
          // Renders combination of select element, with exisitng value correctly selected and validation control
          var $clone = $select.clone();
          $clone.attr('name', 'Phones[' + rows@(unique) + '].PhoneTypeID' ); // changing the phone collection name for serialization
          $clone.find('option[value="' + data + '"]').attr('selected','selected'); // attempting to match existing data

          $clone.attr('data-val', 'true' ); // adding validation
          $clone.attr('data-val-required', 'Phone Type Required' ); // adding error message
          var validation = ' <div><span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows@(unique) + '].PhoneTypeID" data-valmsg-replace="true" </span></div>';

          var selectctl =  $clone.wrap('<div></div>').parent().html();

          // combines both the select control and the validation span element
          return selectctl.concat(validation);
      }}
  , { "data": "PhoneNumber", "title": "Phone Number",
      render : function (data, type, row) {
          // Renders combination of phone number text box, with exisitng value correctly selected and validation control
          var phoneDetail = '<div><input class="form-group" name="Phones[' + rows@(unique) + '].PhoneNumber" placeholder="Number" type="tel" pattern="\d{3}[\-]\d{3}[\-]\d{4}"  value="' + data + '"'
               + ' data-val="true" data-val-required="Phone Required" />'
               + ' <input type="hidden" name="Phones[' + rows@(unique) + '].Id" value="' + row["Id"] + '" />'
               + ' <span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows@(unique) + '].PhoneNumber" data-valmsg-replace="true" /></div>';
          return phoneDetail;
      }}
  , { "data" : "Id",
      render :  function (data,type,row,meta){
          var deleteBtn = '<a class="btn btn-warning removeSelected" href="#">Delete</a>';
          return deleteBtn;
      }
  }
]
});

You need to add "destroy", true. Let it look like the following:

c@(unique) = $('#@(unique)phones').DataTable(
{
    "destroy" : true
    "data" : existingData
, "responsive": true
, "searching" : false        
, "paging": false
, "order": 0
, "createdRow" : function (row, data, index){
    $(row).attr("data-id", index);
    rows@(unique)++;
}
, "columns": [
    { "data": "Id"
       , "visible" : false
    }
  , { "data": "PhoneTypeID", "title": "Phone Type",
      render : function (data, type, row, meta) {
          // Renders combination of select element, with exisitng value correctly selected and validation control
          var $clone = $select.clone();
          $clone.attr('name', 'Phones[' + rows@(unique) + '].PhoneTypeID' ); // changing the phone collection name for serialization
          $clone.find('option[value="' + data + '"]').attr('selected','selected'); // attempting to match existing data

          $clone.attr('data-val', 'true' ); // adding validation
          $clone.attr('data-val-required', 'Phone Type Required' ); // adding error message
          var validation = ' <div><span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows@(unique) + '].PhoneTypeID" data-valmsg-replace="true" </span></div>';

          var selectctl =  $clone.wrap('<div></div>').parent().html();

          // combines both the select control and the validation span element
          return selectctl.concat(validation);
      }}
  , { "data": "PhoneNumber", "title": "Phone Number",
      render : function (data, type, row) {
          // Renders combination of phone number text box, with exisitng value correctly selected and validation control
          var phoneDetail = '<div><input class="form-group" name="Phones[' + rows@(unique) + '].PhoneNumber" placeholder="Number" type="tel" pattern="\d{3}[\-]\d{3}[\-]\d{4}"  value="' + data + '"'
               + ' data-val="true" data-val-required="Phone Required" />'
               + ' <input type="hidden" name="Phones[' + rows@(unique) + '].Id" value="' + row["Id"] + '" />'
               + ' <span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows@(unique) + '].PhoneNumber" data-valmsg-replace="true" /></div>';
          return phoneDetail;
      }}
  , { "data" : "Id",
      render :  function (data,type,row,meta){
          var deleteBtn = '<a class="btn btn-warning removeSelected" href="#">Delete</a>';
          return deleteBtn;
      }
  }
]
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM