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:
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:
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.