Related
I am filling my jQuery Datatable (ver: 1.10.15) from WebAPI and it works but when I search in datatable via searchbox then it doesn't fill the datatable with updated data. Why?
I checked, it sends search value and brings the updated data from server but doesn't populate the table with newly returned data.
function show()
{
$('#example').DataTable({
// "processing": true,
"serverSide": true,
"retrieve": true,
"destroy": true,
"pagination": true,
// "contentType": 'application/json; charset=utf-8',
"ajax": "http://localhost:28071/Users"
});
}
UPDATE:
C# api code:
namespace WebApiHimHer.Controllers
{
public class UsersController : ApiController
{
[HttpGet]
public DTResult GetData([FromUri]DTParameters v)
{
List<string[]> s = new List<string[]>();
//List<basicoperations> s = new List<basicoperations>();
basicoperations bo= new basicoperations();
s = bo.getUsers(v.length, v.start, 1, v.sortOrder, v.search.Value);
DTResult r = new DTResult();
r.draw = 1;
r.recordsFiltered = s.Count;
r.recordsTotal = 100; ;
r.data = s;
return r;
}
}
public class DTResult
{
public int draw { get; set; }
public int recordsTotal { get; set; }
public int recordsFiltered { get; set; }
public List<string[]> data { get; set; }
}
public abstract class DTRow
{
public virtual string DT_RowId
{
get { return null; }
}
public virtual string DT_RowClass
{
get { return null; }
}
public virtual object DT_RowData
{
get { return null; }
}
}
public class DTParameters
{
public int draw { get; set; }
public DTColumn[] columns { get; set; }
public DTOrder[] order { get; set; }
public int start { get; set; }
public int length { get; set; }
public DTSearch search { get; set; }
public string sortOrder
{
get
{
return columns != null && order != null && order.Length > 0
? (columns[order[0].Column].Data + (order[0].Dir == DTOrderDir.DESC ? " " + order[0].Dir : string.Empty))
: null;
}
}
}
public class DTColumn
{
public string Data { get; set; }
public string Name { get; set; }
public bool Searchable { get; set; }
public bool Orderable { get; set; }
public DTSearch Search { get; set; }
}
public class DTOrder
{
public int Column { get; set; }
public DTOrderDir Dir { get; set; }
}
public enum DTOrderDir
{
ASC,
DESC
}
public class DTSearch
{
public string Value { get; set; }
public bool Regex { get; set; }
}
}
I am posting a Request and response after initial table load and after performing a search
After initial load:
Request:
_
1503560388132
columns[0][data]
0
columns[0][name]
columns[0][orderable]
true
columns[0][search][regex]
false
columns[0][search][value]
columns[0][searchable]
true
columns[1][data]
1
columns[1][name]
columns[1][orderable]
true
columns[1][search][regex]
false
columns[1][search][value]
columns[1][searchable]
true
draw
2
length
10
order[0][column]
0
order[0][dir]
asc
search[regex]
false
search[value]
2
start
0
Response:
{"draw":1,"recordsTotal":4,"recordsFiltered":25,"data":[["Hunain","123"],["hk","asd"],["daenerys Targaryen"
,"123"],["",""]]}
After performing a search:
Request:
_
1503560409319
columns[0][data]
0
columns[0][name]
columns[0][orderable]
true
columns[0][search][regex]
false
columns[0][search][value]
columns[0][searchable]
true
columns[1][data]
1
columns[1][name]
columns[1][orderable]
true
columns[1][search][regex]
false
columns[1][search][value]
columns[1][searchable]
true
draw
2
length
10
order[0][column]
0
order[0][dir]
asc
search[regex]
false
search[value]
w
start
0
Response:
{"draw":1,"recordsTotal":1,"recordsFiltered":25,"data":[["Waleed","123"]]}
The reason was that draw parameter being sent and received was not same because I took draw static in the server code so mismatched. I returned the same draw parameter as it was sent.
From the docs :
The draw counter that this object is a response to - from the draw
parameter sent as part of the data request. Note that it is strongly
recommended for security reasons that you cast this parameter to an
integer, rather than simply echoing back to the client what it sent in
the draw parameter, in order to prevent Cross Site Scripting (XSS)
attacks.
Edit
function show(){
$("#example").DataTable({
serverSide: true,
processing: true,
columns : [
{ data : 'FirstName' },
{ data : 'LastName' }
],
ajax: {
url: "https://api.myjson.com/bins/384sr",
dataSrc : ''
}
});
}
show();
Html
<table id="example" class="display">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
Jsfiddle
Not sure if you found your error, but check this out.
Verify the configuration/system.webServer/security/requestFiltering/requestLimits#maxQueryString setting in the applicationhost.config or web.config file.
//For me it was two things.
//wrap the table javascript with
//function _displayItems(data) { var table = $('#...
//Then using the closing brackets:
//destroy then clear
productsTable.destroy();
productsTable.clear();
}
function _displayItems() {
fetch(uri)
.then(response => response.json())
.then(data => _displayItems(data))
.catch(error => console.error('Unable to get items.', error));
}
var tableName = $('#data').DataTable({
"processing": true,
"data": data,
"columns": [
{ "name": "name", "data": "name" },
{ "name": "id", "data": "id" },
{
"render": function (data, type, full, meta) {
var buttonID = "edit_" + full.id;
return '<a id="' + buttonID + '" class="btn btn-outline-info waves-effect editBtn" role="button">Edit</a>';
}
},
{
"render": function (data, type, full, meta) {
var buttonID = "delete_" + full.id;
return ' <a id="' + buttonID + '" onclick="deleteUserRoleModal()" type="button" class="btn btn-outline-danger waves-effect removeRole" role="button">Delete</a>';
}
}
],
"responsive": true,
"dom": 'Bfrtip',
"buttons": [
'copy', 'excel', 'pdf',
{
text: 'Delete',
}
],
"initComplete": function () {
this.api().columns([0]).every(function () {
var column = this;
var select = $('<select class="selectpicker" data-size="5" data-live-search="true"><option value="">Application Role (All)</option></select>')
.appendTo("#table").end()
.on('change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search(val ? '^' + val + '$' : '', true, false)
.draw();
});
column.cells('', column[0]).render('display').sort().unique().each(function (d, j) {
if (column.search() === '^' + d + '$') {
select.append('<option value="' + d + '" selected="selected">' + d + '</option>')
}
else {
select.append('<option value="' + d + '">' + d + '</option>')
}
});
});
},
"bJqueryUI": true,
"bPaginate": false,
"aaSorting": [[1, 'asc']],
"aoPreSearchCols": [[1]],
"lengthMenu": [
[12, 24, 48, 1000],
['12', '24', '48', 'all']
],
"language": {
searchPlaceholder: "🔎 Role Screen ",
search: " ",
}
});
$.fn.dataTable.Buttons(productsTable, {
buttons: [
'copy', 'excel', 'pdf'
]
});
productsTable.buttons().container()
.appendTo($('.col-sm-6:eq(0)', productsTable.table().container()));
$("#todos" + "#table").DataTable({
responsive: true
});
//destroy then clear
productsTable.destroy();
productsTable.clear();
}
Ok, this might be simple, I'm having a simple $.post call to server sending string array as parameters..
$.get('/home/ReadCalPacTagValue', data, function (data) {
data = $.parseJSON(data);
if (data.length != 0) {
var ReadFromDb = data[0]["PushToDb"].replace('PushToDb','ReadFromDb');
var DBAckno = ReadFromDb.replace('ReadFromDb', 'DataAck');
var FIdTag = ReadFromDb.replace('ReadFromDb', 'FluidTypeId');
var UserIdTag = ReadFromDb.replace('ReadFromDb', 'UserId');
var UniqueIdTag = ReadFromDb.replace('ReadFromDb', 'UniqueRecordId');
var dbconnTag = ReadFromDb.replace('ReadFromDb', 'DatabaseConnectionString');
updateTags = [dbconnTag,FIdTag,ReadFromDb, UserIdTag,UniqueIdTag];
actionvalue = ["", fluidtypeid, '1', userid, uniqueID];
var data_Tags = { updateTags: updateTags, actionvalue: actionvalue }
$.post('/home/WriteCalPacTagValue', data_Tags, function (response) {
//var Path = "Config/16_CalPac/" + FluidType + "/" + metername + "/" + FileName
//$.cookie('FileName', FileName, { expires: 7, path: '/' });
//$.cookie('FilePath', Path, { expires: 7, path: '/' });
//$.cookie('ModuleName', "CalPac", { expires: 7, path: '/' });
//window.open('../home/CalPac', '_blank');
});
} else {
swal("Error !", "Data operation tag not binded for this product", "warning");
}
})
my problem is, every time it makes $.post call, server is getting null values int prarameters..
public void WriteCalPacTagValue(string[] updateTags, string[] actionValue)
{
string[] writetags = { };
DanpacUIRepository objNewTag = new DanpacUIRepository();
if (updateTags.Count() > 0)
{
actionValue[0] = ConfigurationManager.AppSettings["DBString"].ToString();
for (int i = 0; i < updateTags.Count(); i++)
{
writetags = updateTags[i].Replace("<", "").Replace(">", ">").Split('>');
objNewTag.WriteTag(writetags, actionValue[i]);
}
}
}
I'm not getting what I've done wrong here.. whereas same function is working from another JS file with some difference string into array updateTags.
any help?
Having
public class DataTags
{
public string[] UpdateTags { get; set; }
public string[] ActionValue { get; set; }
}
At the server: Change the method to this
[HttpPost()]
public void WriteCalPacTagValue([FromBody]DataTags data_Tags)
{
}
At the client: call it
$.ajax({
type: 'POST',
url: '/home/WriteCalPacTagValue',
data: data_Tags,
success: function (response) {
//your code
}
});
Also you can send the whole data as json string using data: JSON.stringify(data_Tags), in javascript code the change the WriteCalPacTagValue to accept a single string at the parameter and deserialize it in C# code at the server side.
EDIT if you cannot change the server side code, you may follow this as stated in the comments.
I would like to know how to convert the following object to C# when reaching the mathod. I needed to create an object which can hold multiple array's within JSON something like the following
{
"cars": {
"Ferrari":["LaFerrari","F40","458"],
"Porsche":["911","959"],
"Lamborghini":["Aventador"]
}
}
The code I used is the following within cshtml
<div class="row">
<div class="col-md-4">
<div>
<input type="text" id="txtKey" />
<input type="button" id="btnKey" />
</div>
<div>
<input type="text" id="txtChild" />
<input type="button" id="btnChild" />
</div>
<div>
<input type="button" id="btnSubmit" />
</div>
</div>
</div>
#section scripts
{
$(function () {
AddKeyToDictionary('Ferrari');
AddKeyToDictionary('Porsche');
AddKeyToDictionary('Lamborghini');
AddValueToDictionary('Ferrari', 'LaFerrari');
AddValueToDictionary('Ferrari', 'F40');
AddValueToDictionary('Ferrari', '458');
AddValueToDictionary('Porsche', '911');
AddValueToDictionary('Porsche', '959');
AddValueToDictionary('Lamborghini', 'Aventador');
$('#btnKey').click(function () {
AddKeyToDictionary($('#txtKey').val());
});
$('#btnChild').click(function () {
AddValueToDictionary($('#txtKey').val(), $('#txtChild').val());
});
$('#btnSubmit').click(function () {
submit();
});
});
var dict = {};
function AddKeyToDictionary(key) {
dict[key] = [];
}
function AddValueToDictionary(key, value) {
dict[key].push(value);
}
function submit() {
var url = "#Url.Action("UpdateCustomFields", "Home")";
var data = JSON.stringify({ 'cars': dict });
$.ajax({
type: "POST",
contentType: "Application/json;charset=utf-8",
url: url,
data: data,
datatype: "json",
success: function (msg) {
},
error: function (request, status, error) {
displayDialog("A communication Error has occurred, please contact IT support: " + error);
}
});
}
</script>
}
I've tried the following within MVC (got this from a JSON c# convertor)
public JsonResult UpdateCustomFields(RootObject cars)
{
return Json("");
}
}
public class Cars
{
public List<string> Ferrari { get; set; }
public List<string> Porsche { get; set; }
public List<string> Lamborghini { get; set; }
}
public class RootObject
{
public Cars cars { get; set; }
}
The car makes should be dynamic and then the arrays below should be converted correctly.
I also tried to iterate through the array and changed them all to key value pairs which still wasn't rendering
function convertToKeyValue() {
submitValue = [];
for (var k in dict) {
if (dict.hasOwnProperty(k)) {
if (dict[k].length > 0) {
for (var i = 0; i < dict[k].length; i++) {
submitValue.push({ key: k, value: dict[k][i] });
}
} else {
submitValue.push({ key: k, value: '' });
}
}
}
}
Passing them through the name/value pairs I was able to see them in the dynamic property within the controller but can't get to the variables.
public JsonResult UpdateClientCustomFields(object cars)
{
var result = customFields.XmlSerializeToString();
return Json("hello");
}
If anyone can help or point me in the right direction.
Thanks
Updated: I've had to convert the javascript array to a list of key pairs (not ideal) and use List> cars as the paramter, the model is not ideal, but will use this until I find a better way.
Here is the updated code
HTML
<input type="button" id="btnSubmit2" />
var submitValue = [];
function convertToKeyValue() {
submitValue = [];
for (var k in dict) {
if (dict.hasOwnProperty(k)) {
//alert("Key is " + k + ", value is" + dict[k]);
//alert("KEY: " + k);
if (dict[k].length > 0) {
for (var i = 0; i < dict[k].length; i++) {
//alert("childrec: " + dict[k][i]);
submitValue.push({ key: k, value: dict[k][i] });
}
} else {
submitValue.push({ key: k, value: '' });
}
}
}
}
function submit2() {
convertToKeyValue();
var url = "#Url.Action("UpdateCustomFields2", "Home")";
var data = JSON.stringify({ 'cars': submitValue });
$.ajax({
type: "POST",
contentType: "Application/json;charset=utf-8",
url: url,
data: data,
datatype: "json",
success: function (msg) {
},
error: function (request, status, error) {
}
});
}
MVC
public JsonResult UpdateCustomFields2(List<Dictionary<string, string>> cars)
{
return Json("");
}
Try changing your cars property in RootObject to public Dictionary<string,List<string>> cars {get; set;}
Try to make your input param as string and then deserialize it to your object.
public JsonResult UpdateCustomFields(string cars)
{
RootObject yourCars = JsonConvert.DeserializeObject<RootObject>(cars);
return Json("");
}
Good luck :)
Unless I am missing something, the following seems to work fine
public class Program
{
public void Main(string[] args)
{
var json = #"
{
""cars"": {
""Ferrari"":[""LaFerrari"",""F40"",""458""],
""Porsche"":[""911"",""959""],
""Lamborghini"":[""Aventador""]
}
}
";
var dataObj = JsonConvert.DeserializeObject<Data>(json);
}
public class Data
{
public Dictionary<string, List<string>> Cars { get; set; }
}
}
Which version of JSON.NET are you using? I remember older versions had issues with dictionaries, but you could probably just create your own converter if that is the case.
I have multiple parameters which I have to pass to api controller.
What I was doing is
In my javascript
var routeInfo = JSON.stringify(routes);
var colors = JSON.stringify(colorsArray);
var times = JSON.stringify(mytimeArray);
var distances = JSON.stringify(myDistancArray);
var dir = $("#Direction").val();
var fullString = routeInfo + ";" + colors + ";" + times + ";" + distances+";"+dir;
$.post("api/HomeToSchool/?route=" + fullString,
function (data) {
if (data = true) {
alert("Routes Saved Successfully");
}
else if (data = false) {
alert("Routes are not saved");
}
});
& in my Controller
public bool PostHomeToSchoolRoutes([FromUri]string route)
{
// my logic
}
Here I am just getting values of "routeInfo" & other values are not comming.
e.g.
var routeInfo = [["Børge,Brogade 38, 4100, Ringsted,09:25:00,55.43953, 11.79043","Grete,Sjællandsgade 27, 4100, Ringsted,09:25:00,55.44024, 11.78852","Else,Fynsgade 14, 4100, Ringsted,09:25:00,55.44128, 11.78595","Birthe,Eksercerpladsen 47, 4100, Ringsted,09:25:00,55.44954, 11.80309","Knud Lavard Centret, Eksercerpladsen 3, 4100, Ringsted,370,55.45014, 11.80474"]]
var colors = ["#886A52"]
var times = [7.97]
var distances = [3.36]
var dir = 0
What I get in my Controller is
[["Børge,Brogade 38, 4100, Ringsted,09:25:00,55.43953, 11.79043","Grete,Sjællandsgade 27, 4100, Ringsted,09:25:00,55.44024, 11.78852","Else,Fynsgade 14, 4100, Ringsted,09:25:00,55.44128, 11.78595","Birthe,Eksercerpladsen 47, 4100, Ringsted,09:25:00,55.44954, 11.80309","Knud Lavard Centret, Eksercerpladsen 3, 4100, Ringsted,370,55.45014, 11.80474"]];["
Other values are not coming.
Whats wrong I am doing here.
I'm afraid that your url is too long (>255 characters), You can try this.
$.ajax({
type: 'POST',
url:"api/HomeToSchool",
data:{routeInfo:routes,colors:colorsArray,times:mytimeArray,distances:myDistancArray,dir:dir},
dataType: "json",
traditional:true,
function (data) {
if (data = true) {
alert("Routes Saved Successfully");
}
else if (data = false) {
alert("Routes are not saved");
}
}
});
and your controller:
public bool PostHomeToSchoolRoutes(string[] routeInfo,string[] colors,double[] times,double[] distances,int dir)
{
// my logic
}
I see that you're using 2-dimensional array for routeInfo. But there is only 1 item, i think you should change it to 1-dimensional array to make it compatible with the controller code string[] routeInfo
Far too much information going into the URL here, not only that your not correctly appending the parameters together they need to be separated using & not ;.
On top of that, your not really taking advantage of the MVC capabilities here. At the client side you want to send up your information as a collective object rather than individual parameters e.g.
var schoolRoutes = {
routes: routes,
colors: colorsArray,
times: mytimeArray,
distances: myDistanceArray,
direction: $("#Direction").val()
};
$.ajax({
type: 'POST'
url: "api/HomeToSchoolRoutes",
data: JSON.stringify(schoolRoutes),
dataType: "json",
success: function (data) {
if (data = true) {
alert("Routes Saved Successfully");
}
else if (data = false) {
alert("Routes are not saved");
}
});
Then at the server side, introduce a class which will be able to bind to the incoming data aka a ViewModel
public class RouteInfoViewModel
{
...
}
public class SchoolRoutesViewModel
{
public RouteInfoViewModel[] Routes { get; set; }
public string[] Colours { get; set; }
public double[] Times { get; set; }
public double[] Distances { get; set; }
public string Direction { get; set; }
}
Then update your action to expect this particular ViewModel and that should give you access to all the information posted.
public bool PostHomeToSchoolRoutes(SchoolRoutesViewModel schoolRoutes)
{
...
}
I am using jEditable and am wondering if if it is possible to have a select (type=select) with optgroups?
I have managed to do this by creating a custom input type (I called it optgroup).
It works on the assumption the json for data is in the form;
var json = [{"Foo":[{"id":1,"name":"aaa"},{"id":2,"name":"bbb"}]},{"Bar":[{"id":3,"name":"ccc"},{"id":4,"name":"ddd"}]}];
This is the code;
optgroup: {
element : function(settings, original) {
var select = $('<select class="opt" />');
$(this).append(select);
return(select);
},
content : function(data, settings, original) {
if (String == data.constructor) {
eval ('var json = ' + data);
} else {
var json = data;
}
var addto = $('select', this);
$.each(json, function(i, optgroups) {
$.each(optgroups, function(groupName, options) {
var $optgroup = $("<optgroup>", {label: groupName});
$optgroup.appendTo(addto);
$.each(options, function(j, option) {
var $option = $("<option>", {text: option.name, value: option.id});
$option.appendTo($optgroup);
});
});
});
}
}
To use;
$('.editable').find('td').editable(
function(v, s) {
// do whatevere you need to...
},
{
"data" : [{"Foo":[{"id":1,"name":"aaa"},{"id":2,"name":"bbb"}]},{"Bar":[{"id":3,"name":"ccc"},{"id":4,"name":"ddd"}]}],
"indicator": 'Saving ...',
"tooltip": 'Double Click to edit',
"type": 'optgroup',
"submit": 'Save changes',
"event": 'dblclick'
}
);
You have to add
optgroup: {
element: function (settings, original) {
var select = $('<select />');
$(this).append(select);
return (select);
},
content: function (data, settings, original) {
if (String == data.constructor) {
eval('var json = ' + data);
} else {
var json = data;
}
var addto = $('select', this);
$.each(json, function (i, optgroups) {
$.each(optgroups, function (groupName, options) {
var $optgroup = $("<optgroup>", {
label: groupName
});
$optgroup.appendTo(addto);
$.each(options, function (j, option) {
var $option = $("<option>", {
text: option.name,
value: option.id
});
if (option.selected !== null && option.selected !== undefined && option.selected) {
$option.attr('selected', 'selected');
}
$option.appendTo($optgroup);
});
});
});
}
}
into your jquery.jeditable.js, find "types" and paste into that array. After that you file should look like:
types: {
textarea:...,
select:...
number:...
...
optgroup:...
}
Next you have to use it.
$("#yourControlSelect").editable("/controllerName/ActionToExecute", {
data: #Html.Action("JEditbaleOptGroup", "ControllerName"),
type: 'optgroup', //Same as you created before
...
});
Remember the format of data, it has to be:
[
{"Category1": [{"id": 1,"name": "Product1"}, {"id": 2,"name": "Product2"}]},
{"Category2": [{"id": 3,"name": "Product3"}, {"id": 4,"name": "Product4"}]},
{"Category3": [{"id": 5,"name": "Product5"}, {"id": 6,"name": "Product6"}]}
]
Finally, here's the model to create and return it
public class JEditable
{
public string Id { get; set; }
public string Descripcion { get; set; }
}
public class JEditableOptGroup
{
public string Nombre { get; set; }
public IEnumerable<JEditable> Hijos { get; set; }
}
Fill the model
var grupos = Repositorio.SelectListOfYourDataType(x => true).GroupBy(x => x.ColToGrouping);
foreach (var grupo in grupos)
{
List<JEditable> hijos = new List<JEditable>();
foreach (var item in grupo.OrderBy(x=>x.nombre_g5))
hijos.Add(new JEditable() { Id = item.Id_g5, Descripcion = item.nombre_g5.Trim() + " (" + item.Balance_g5 + ") " + item.cuenta_g5.Trim() });
jEditable.Add(new JEditableOptGroup() { Nombre = grupo.Key + " " + grupo.FirstOrDefault().cuenta_g4.Trim(), Hijos = hijos });
}
return Funciones.JEditableDropDownList(jEditable);
Tranform data to the correct format:
internal static string JEditableDropDownList(List<JEditableOptGroup> grupos)
{
StringBuilder sb = new StringBuilder();
sb.Append("[");
foreach (var grupo in grupos)
{
StringBuilder hijos = new StringBuilder();
foreach (var item in grupo.Hijos)
hijos.Append("{" + string.Format("id:'{0}',name:'{1}'", item.Id, item.Descripcion) + "},");
sb.Append("{" + string.Format("'{0}':[{1}]", grupo.Nombre, hijos) + "},");
}
sb.Append("]");
return sb.ToString();
}
Enjoy it!