Got a nice JSON problem over here;
I don't know how to go about formatting date, timespan, decimals etc before sending it to the view in MVC. I'm using the datatables jQuery plugin, and my 'DataHandler' method returns a JSON object as source for the datatable.
When I was processing the data and filtering client-side it was pretty straightforward, but now I'm processing the data on the server-side.
Controller:
public JsonResult DataHandler(DTParameters param)
{
try
{
var dtsource = new List<spRegistrations_Result>();
using (entities dc = new entities())
{
dtsource = dc.spRegistrations().ToList();
}
List<String> columnSearch = new List<string>();
foreach (var col in param.Columns)
{
columnSearch.Add(col.Search.Value);
}
List<spRegistrations_Result> data = new ResultSet().GetResult(param.Search.Value, param.SortOrder, param.Start, param.Length, dtsource, columnSearch);
int count = new ResultSet().Count(param.Search.Value, dtsource, columnSearch);
DTResult<spRegistrations_Result> result = new DTResult<spRegistrations_Result>
{
draw = param.Draw,
data = data,
recordsFiltered = count,
recordsTotal = count
};
return Json(result);
}
catch (Exception ex)
{
return Json(new { error = ex.Message });
}
}
Table initialization:
var table = $('#myTable').DataTable({
responsive: true,
"serverSide": true,
"ajax": {
"type": "POST",
"url": '/Table/DataHandler',
"contentType": 'application/json; charset=utf-8',
'data': function (data) { return data = JSON.stringify(data); }
},
"drawCallback": function(settings){
$('.card').hide();
},
"paging": true,
"deferRender": true,
"columns": [
{ "data": "RegId" },
{ "data": "PresenceDate" }, etc...
Model:
public int RegId { get; set; }
public System.TimeSpan StartTime { get; set; }
public System.TimeSpan EndTime { get; set; }
public System.DateTime PresenceDate { get; set; }
This is how it looks when the table is displayed
As you can see, the date is not very nicely formatted, and is the reason that I want to format the data before displaying it. Same goes for a couple of TimeSpan objects etc that I eventually want to show in the table.
I'm still pretty new to ajax, and don't know how to go about this the easiest way. Thanks for any input !
You could use the columns.render property to define the content of the table cell, using a custom js function to format the date. Something like:
...
"render": function ( data, type, full, meta ) {
var date = new Date(parseInt(data.substr(6), 0));
return ISODateString(date);
}
The function to format the date dd/mmm/yyyy:
function ISODateString(d) {
function pad(n) { return n < 10 ? '0' + n : n }
return pad(d.getDate()) + '/' + pad(d.getMonth() + 1) + '/' + d.getFullYear();
}
Related
I am trying to pass LINQ join query result(joining three tables ) from the controller to Ajax success function from Json Result but I am not getting any value means success function did not run and it executes error function . the query generated the correct result and also when I placed the breakpoint on return Json(query) or return new JsonResult{ Data = query, JsonRequestBehavior = JsonRequestBehavior.AllowGet };, the query variable contains the data . the problem is that the generated query result is not passed from the controller to the ajax function. I have tried other possible solutions but did not get any success.
Note : I have created model class to store the join query result.
any guidance regarding this will highly be appreciated
Thanks in advance.
here my controller code
[HttpPost]
public JsonResult getscore(int val)
{
Debug.WriteLine("checking {0}", val);
var g = val;
List<Participant_info> p_details = context.Participant_info.ToList();
List<Participant_enrolled> e_details = context.Participant_enrolled.ToList();
List<Contest_marking> mark = context.Contest_marking.ToList();
var query = (from p in p_details
join e in e_details on p.stud_id equals e.stud_id
join m in mark on e.E_id equals m.E_id
select new ScoreViewModel
{
partVm = p,
enrollVm = e,
markVm = m
}).ToList();
foreach (var u in query)
{
Debug.WriteLine("name {0} mark{1} Contest_id {2} ", u.partVm.stud_name, u.markVm.C1st_marks, u.enrollVm.Contest_id);
}
return Json(query, JsonRequestBehavior.AllowGet);
//return new JsonResult { Data = query, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
Model class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace CEN_CONTEST_MGT_SYSTEM.Models
{
public class ScoreViewModel
{
public Participant_info partVm { get; set; }
public Participant_enrolled enrollVm { get; set; }
public Contest_marking markVm { get; set; }
}
}
View code
#model IEnumerable<CEN_CONTEST_MGT_SYSTEM.Models.ScoreViewModel>
#{
ViewBag.Title = "score";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>score</h2>
#Html.DropDownList("Trial", "--- Tous ---")
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script type="text/javascript">
$("#Trial").change(function () {
val = $("#Trial").val();
alert("fff" + val);
//var data = JSON.stringify({
// 'val': val
//});
$.ajax({
type: "POST",
url: "/judge_dashboard/getscore",
data: JSON.stringify({'val': val}),
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
processData: false,
cache: false,
success: function (data) {
alert("hello");
},
error: function () {
alert("error");
}
})
})
</script>
try to change the action
public ActionResult<List<ScoreViewModel>> getscore(int val)
{
... your code
return Ok(query);
}
When using this:
select new ScoreViewModel
{
partVm = p,
enrollVm = e,
markVm = m
}
Likely what's happening is the serialization process is also processing all of your child objects, and may be running into a problem with that. Is there any error that you are receiving? I have a feeling the serialization process might be complicating it.
To test that, try returning all the properties you need directly such as:
return Json(new {
x = vm.partVm.X,
y = vm.enrollVm.Y
}, JsonRequestBehavior.AllowGet);
I have a spring boot server and i am able to generate a streaming table on client side by sending json one after the another. The problem is if a user logs in say after 10 minutes, he is only able to access data starting from 10th minute i.e he is not able to access data from 0 to 10th minute. What i want is to push the data from 0th to 10th minute first and at the same time continue the streaming process. How can this be done? I am using jquery datatable to generate the table.
I am attaching the controller and client side html for reference
1) Controller
#Controller
public class ScheduledUpdatesOnTopic {
#Autowired
private SimpMessagingTemplate template;
int count=0;
#Scheduled(fixedDelay=500)
public void trigger() {
DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
String str[] = {"name"+count,""+Math.round(Math.random()*100),"India"+Math.round(Math.random()*100),df.format(date)};
this.template.convertAndSend("/topic/message",str);
++count;
}
}
2) Client HTML
var _self = this;
$(document).ready(function() {
var message ;
$('#tbl').DataTable( {
data: message,
"aLengthMenu" : [[25,50,75,-1],[25,50,75,"All"]],
"pageLength" :25,
columns: [
{ title: "Name" },
{ title: "Age" },
{ title: "Country" },
{ title: "Date"}
]
});
subscribeSocket();
});
function addRow(message){
var table = $('#tbl').DataTable();
if(table && message ){
table.row.add(message).draw();
}
}
function subscribeSocket(){
var socket = new SockJS('/gs-guide-websocket');
var stompClient = Stomp.over(socket);
stompClient.connect({ }, function(frame) {
stompClient.subscribe("/topic/message", function(data) {
message = JSON.parse(data.body);
_self.addRow(message);
});
});
};
If you don't save previous sent datas, you can't send them back to new customers.
On the front side, you have to subscribe to an "history" resource and make a call to get it.
Front:
function subscribeSocket() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
var firstCounterReceived = null;
stompClient.connect({}, function (frame) {
setConnected(true);
stompClient.subscribe('/topic/history', function (response) {
console.log(JSON.parse(response.body));
});
stompClient.subscribe('/topic/message', function (response) {
var message = JSON.parse(response.body);
if (firstCounterReceived == null) {
firstCounterReceived = message[0];
console.log(`Calling history endpoint with ${firstCounterReceived}`);
stompClient.send("/app/topic/history", {}, message[0]);
}
console.log(message);
});
});
}
Back:
#Controller
#EnableScheduling
public class ScheduledUpdatesOnTopic {
Map<Integer, String[]> history = new LinkedHashMap<>();
#Autowired
private SimpMessagingTemplate template;
private Integer count = 0;
#MessageMapping("/topic/history")
#SendTo("/topic/history")
public List<String[]> history(Integer to) {
return history.keySet()
.stream()
.filter(counter -> counter < to)
.map(counter -> history.get(counter))
.collect(Collectors.toList());
}
#Scheduled(fixedRate = 500)
public void sendMessage() {
DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
String[] str = {count.toString(), "name"+count,""+Math.round(Math.random()*100),"India"+Math.round(Math.random()*100),df.format(date)};
history.put(count, str);
this.template.convertAndSend("/topic/message",str);
++count;
}
}
In this sample, saved datas are stored in a map, be aware that it will consume some memory at some point.
I have seen & tried a lot of codes to increase the JSON limit like in
1. web.config
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483647"/>
</webServices>
</scripting>
</system.web.extensions>
2.JSonControllerFactory
public sealed class CustomJsonValueProviderFactory : ValueProviderFactory
{
private static void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)
{
IDictionary<string, object> d = value as IDictionary<string, object>;
if (d != null)
{
foreach (KeyValuePair<string, object> entry in d)
{
AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
}
return;
}
IList l = value as IList;
if (l != null)
{
for (int i = 0; i < l.Count; i++)
{
AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
}
return;
}
// primitive
backingStore[prefix] = value;
}
Down here in GetDeserializedObject() i am getting bodytext as empty and unable to set the max property.
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// not JSON request
return null;
}
StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
string bodyText = reader.ReadToEnd();
if (String.IsNullOrEmpty(bodyText))
{
// no JSON data
return null;
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = int.MaxValue; //increase MaxJsonLength. This could be read in from the web.config if you prefer
object jsonData = serializer.DeserializeObject(bodyText);
return jsonData;
}
}
script [down data: jQuery("#geomaster").serialize() contains data. If it is below 100 points the data is saving successfully. if it crosses 100 points, not hitting the controller SaveGeodata method(i mean not posting to controller)].
jQuery.ajax({
type: "GET",
url: "SaveGeodata",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: jQuery("#geomaster").serialize(),
success: function (data) {
alert("Geofence Created Successfully");
},
error: function (msg) {
alert("Error");
}
});
Is there any way where i can attach the maxJsonSize property in script itself.
Any other possible means which could help in posting max data to controller is really thankful.
The Problem
When I post jSon data to webapi, using pt-br formats (dd/mm/yyyy for date and comma decimal separator for float), the values are deserialized as en-us formats resulting in error.
i.e.
» date: posting 23/01/2013 becames 01/01/0001
» float: posting 1,4 becames 0.0
The Help Request
Can anybody help me to define "the ultimate" solution to post data to web api using other cultures than en-US.
I've read a few discussions but none of them presents the complete solution, or even a working solution.
Considering the following
Model:
public class Person
{
public Datetime BirthDate { get; set; }
public double Weight { get; set; }
}
ApiController Method
public HttpResponseMessage Create(Person person)
{
// ...
}
AjaxCall
$.ajax({
type: 'POST',
url: sl.baseUri + "/create",
data: "Weight=87%2C7&BirthDate=17%2F07%2F1981",
success: null,
dataType: "json",
})
** I already added the following globalization settings to the web.config
<globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="pt-BR" uiCulture="pt-BR"/>
You could try posting it as a JSON object rather than a plain string:
{"BirthDate": "17/07/1981", "Weight": "87,7"}
However, you would need to tell Json.Net what date format to expect:
http://james.newtonking.com/archive/2009/02/20/good-date-times-with-json-net.aspx
To solve this issue, I created a custom binding for dates.
ko.bindingHandlers.date = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
ko.utils.registerEventHandler(element, 'change', function () {
var value = valueAccessor();
if (element.value !== null && element.value !== undefined && element.value.length > 0) {
value(element.value);
}
else {
value('');
}
});
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var value = valueAccessor();
var valueUnwrapped = ko.utils.unwrapObservable(value);
var output = '';
if (valueUnwrapped !== null && valueUnwrapped !== undefined && valueUnwrapped.length > 0) {
output = moment(valueUnwrapped).format('YYYY-MM-DD');
}
if ($(element).is('input') === true) {
$(element).val(output);
} else {
$(element).text(output);
}
}
};
This binding keeps the date in the following format: 2014-11-05T00:00:00-02:00
It is recommended that you use a input type=date in your html.
Also, you'll need to include the moment.js library to your project.
I have a <select> which is loaded by a JSon. But I want to use "#html.dropdownlist helper" instead. My Json is:
function LoadSites() {
$("SelectSite").html("");
$.getJSON("/Pedido/GetSite", null, function (data) {
$("#SelectSite").append("<option value=0>Selecione...</option>");
$.each(data.Result, function (index, site) {
$("#SelectSite").append("<option value='" + site.Id + "'>" + site.Nome + "</option>");
});
});
this Json populate this...
<select id="SelectSite"></select>
My Controller:
[HttpGet]
public JsonResult GetSite()
{
Repository<Site> siteRepo = new Repository<Site>( unitOfWork.Session );
return this.Json( new { Result = siteRepo.All() }, JsonRequestBehavior.AllowGet );
}
I want my code more reusable and self-documenting.
How can I send the object "site" from JSon to "cshtml" using dropdownlist to do something like #html.dropdownlist(site.id, site.Nome)???
Is there a way?
Tks guys.
In your view:
#Html.DropDownListFor(x => x.SiteId, new SelectList(Enumerable.Empty<SelectListItem>()))
where SiteId is a property of your view model which will receive the selected site id when the form is submitted.
and then you could populate this dropdown using AJAX:
$(function() {
$.getJSON('#Url.Action("GetSite", "Pedido")', function(result) {
var ddl = $('#SiteId');
ddl.empty();
$(result).each(function() {
ddl.append(
$('<option/>', {
value: this.Id
}).html(this.Nome)
);
});
});
});
and the controller action that would return the JSON data:
public ActionResult GetSite()
{
var sites = new[]
{
new { Id = "1", Nome = "site 1" },
new { Id = "2", Nome = "site 3" },
new { Id = "3", Nome = "site 3" },
};
return Json(sites, JsonRequestBehavior.AllowGet);
}