I am posting data to a controller stringified by knockout:
var data = ko.toJSON(viewModel);
$.ajax({
type: 'POST',
url: '#Url.Action("Action")',
data: { data: data },
dataType: 'json'
....
})
Then server-side, I try to deserialize the data with JsonConvert.
var viewModel = JsonConvert.DeserializeObject<ViewModel>(data,
new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Local,
DateFormatHandling = DateFormatHandling.IsoDateFormat
});
This fails if data contains null values (serialized as "NaN"), looking like this:
"MyField":"NaN"
Without null values, it works fine.
I tried adding NullValueHandling = NullValueHandling.Include/Ignore to the serializer settings, both without success.
I got around the problem by adding a small replacer function to the knockout stringifier (as suggested by DavidG - thank you, I should have made this work from the beginning).
var data = ko.toJSON(viewModel, function (key, value) {
if (value == "NaN") {
return;
}
else {
return value;
}
});
I'm trying to code a simple autocomplete using LINQ to entities and Razor (new to c# sharp as well) and i'm having trouble displaying json data in my view.
My controller is as follows:
public ActionResult AutoCompleteCity(string guess)
{
List<City> listData = null;
if (!string.IsNullOrEmpty(guess))
{
listData = db.AutoCompleteCity(guess);
}
return Json(new { Data = listData });
}
AJAX call:
function getCities(input) {
var serviceURL = $("#autocompleteURL").val();
var url =
$.ajax({
type: "POST",
url: serviceURL,
data: {
'guess': input
},
dataType: 'json',
success: function (response) {
if (response.Data != null) {
if ($("#targetUL") != undefined) {
$("#targetUL").remove();
}
Data = response.Data;
$.each(Data, function (i, value) {
$("#targetUL").append($("<li class='targetLI' onclick='javascript:agregarTexto(this)'>" + JSON.stringify(value) + "</li>"));
});
});
}
I might be missing a bracket or two :D
Any way when i retrieve records from the database and try to pass JSON values to the view the output is:
{"Data":[{"Selected":false,"Text":null,"Value":null}]}
I assume I'm not passing the JSON listData correctly. Any input will be greatly appreciated, thanks!
EDIT: here is a screencap of the values returned by listData in my controller
This is my LINQ query
public List<City> AutoCompleteCity(string guess)
{
using (var context = new Sports.SportsEntities())
{
var query = (from loc in context.city
join prov in context.state on loc.STATE_ID equals prov.STATE_ID
where loc.CITY_DESC.Contains(guess.ToUpper())
select new
{
city = loc.CITY_DESC,
state = prov.STATE_DESC,
});
IEnumerable<City> cityList= from ba in query.AsEnumerable()
select new City(ba.city, ba.state);
return cityList.ToList();
}
}
This error:
{"Data":[{"Selected":false,"Text":null,"Value":null}]}
was caused by having declared private attributes in the City Class, or by failing to declare getter/setter methods if said attributes are meant to be private.
I figured that out by looking at the screen capture posted on my question, only displaying the "selected", "text" and "value" properties and not the city and state description in the query results, which was what I needed to display below the textbox input.
This controller method will do the trick:
public JsonResult AutoCompleteCity(string term)
{
List<City> listData = new List<City>();
if (!string.IsNullOrEmpty(term))
{
listData = db.AutoCompleteCity(term);
}
return Json(listData, JsonRequestBehavior.AllowGet);
}
The problem is probably this piece of code in the AJAX call:
if ($("#targetUL") != undefined) {
$("#targetUL").remove();
}
By doing this you are removing the ul tag from the DOM and therefore cannot add the li elements you are constructing in this piece of code:
$.each(Data, function (i, value) {
$("#targetUL").append($("<li class='targetLI' onclick='javascript:agregarTexto(this)'>" + JSON.stringify(value) + "</li>"));
});
If you want to clear the list use .empty():
if ($("#targetUL") != undefined) {
$("#targetUL").empty();
}
if you want to return a JSON, change that:
public ActionResult AutoCompleteCity(string guess)
by
public JsonResult AutoCompleteCity(string guess)
and also try that:
Data = JSON.parse(response.Data);
It looks like your method returns a list of City objects, so maybe you need to use the property of that objects to get to the city name, something like this:
$.each(Data, function (i, city) {
$("#targetUL").append($("<li class='targetLI' onclick='javascript:agregarTexto(this)'>" + city.Name + "</li>"));
});
I have a drop down list that I need to fill with datetime values passed from an ajax call. The values that populate look like this: "/date1234847269/" and not actual dates. I just need the dates to be passed into the drop down list. I do not need the time stamps that are also in the datetime value that is returned from the controller.
I'm not sure if jQuery has issues with handling c# datetime values and not strings. Any help would be appreciated. Thanks
My View:
<select id="ddlDate" class="form-control bold">
<option value='0'>--Select Date--</option>
</select>
My Ajax Call:
function loadDateDDL(historicalIsChecked, monthlyIsChecked) {
$.ajax({
type: 'POST',
url: '#Url.Action("GetGroupReportDates")',
dataType: 'json',
data: { isMonthly: monthlyIsChecked },
success: function (returnData) {
convertDate(returnData);
$("#ddlDate").empty();
$("#ddlDate").append("<option value='0'>--Select Date--</option>");
$.each(returnData, function (value, key) {
$("#ddlDate").append($("<option></option>")
.attr("value", value).text(key));
});
//alert(returnData);
},
error: function (ex) {
alert('Failed to retrieve dates.' + ex);
}
});
}
function convertDate(returnData)
{
var date = new Date(returnData);
return date;
}
My Controller:
public JsonResult GetGroupReportDates ( Boolean isMonthly )
{
List<DateTime> reportDates = RealmsModel.RealmsAuditDataInterface ( ).GetGroupQueryRptDates ( isMonthly );
return new JsonResult ( )
{
Data = reportDates,
MaxJsonLength = Int32.MaxValue
};
}
Update 1/21/2016:
I am now passing my json data "returnData" to the javascript function below and converting it based on another stack post: How do I format a Microsoft JSON date?
function convertDate(returnData)
{
var date = new Date(returnData);
return date;
}
This now gives me the error "date = Invalid Date {}, returnData = ["/Date(1451628000000)/"]". I feel like I'm getting close. Any help is appreciated.
I resolved this with the following:
function convertDate(returnData)
{
var pattern = /Date\(([^)]+)\)/;
var results = pattern.exec(returnData);
var dt = new Date(parseFloat(results[1]));
return (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
}
The format you're seeing is the old "microsoft" way of formatting dates. There are 2 ways to get around it.
One way would be to use the JSON.Net serialiser instead of the built in JavaScriptSerializer, as it (since version 4.5) formats dates so that they can be automatically parsed.
Another (quicker) way would simply be to extract the numbers from the date in it's current format as pass them to a new javascript Date object.
function toDate(value) {
return new Date(parseInt(/Date\(([^)]+)\)/.exec(value)[1], 10));
}
I have a controller action like this:
List<string> abcd = new List<string>()
foreach (var i in images)
{
abcd.Add("{url:'"+GetImageUrl(i)+"'}");
}
return Json(abcd, JsonRequestBehavior.AllowGet);
So the output of abcd is
["{url:'/PropertyImage/GetPropertyImage?imageId=1'}", "{url:'/PropertyImage/GetPropertyImage?imageId=2'}", "{url:'/PropertyImage/GetPropertyImage?imageId=8'}"]
But the result I want is:
images:[{url:'/PropertyImage/GetPropertyImage?imageId=1'}, {url:'/PropertyImage/GetPropertyImage?imageId=2'}, {url:'/PropertyImage/GetPropertyImage?imageId=8'}]
In my JavaScript, I have
$.ajax({
type: "GET",
url: url,
success: function (result) {
console.log(JSON.stringify(result));
var data = {
images: [result]
};
template = "{{#images}}<a href='{{url}}'><img class='imageborder' src='{{url}}' style='width:150px;height:150px'></img></a>{{/images}}";
renderedOutput= Mustache.to_html(template,data);
$('#Propertyimagelinks').html(renderedOutput);
}
});
How can I get the correct output?
Rather than trying to manually manipulate JSON strings, it seems a lot simpler to use ASP.NET MVC's built in JSON serialization functionality and a little bit of Linq, like this:
var abcd = images.Select(i => new { url = GetImageUrl(i) }).ToList();
return Json(abcd, JsonRequestBehavior.AllowGet);
And in your JavaScript result handler, use this:
var data = { images: result };
Alternatively you can use this in your controller:
var abcd = images.Select(i => new { url = GetImageUrl(i) }).ToList();
return Json(new { images = abcd }, JsonRequestBehavior.AllowGet);
And in your JavaScript:
var data = result;
I have a WebMethod that returns at date {"d":["/Date(1390411800000)/"]}:
[WebMethod]
public static object getBreadCrumbDate(int projectID, int statusID)
{
using (dbPSREntities5 myEntities = new dbPSREntities5())
{
var thisId = myEntities.tbBreadCrumbs.Where(x => x.ProjectID == projectID && x.StatusID == statusID).Max(x => x.BreadCrumbID);
var columns = myEntities.tbBreadCrumbs.Where(x => x.BreadCrumbID == thisId)
.Select(x => x.CreateDateTime).ToList();
return columns;
}
}
and I want to format it "mmm dd, yy" (Jan 22, 14) and return it to the calling AJAX but not sure the best way. Here's my AJAX:
function getBreadCrumbDate(projectID, statusID) {
$.ajax({
url: "view-requests.aspx/getBreadCrumbDate", // Current Page, Method
data: JSON.stringify({
projectID: projectID,
statusID: statusID
}), // parameter map as JSON
type: "POST", // data has to be POSTed
contentType: "application/json", // posting JSON content
dataType: "JSON", // type of data is JSON (must be upper case!)
timeout: 10000, // AJAX timeout
success: function (result) {
$("#divApprovedStatus").html(result.d[0]);
},
error: function (xhr, status) {
alert(status + " - " + xhr.responseText);
}
});
}
Right now it prints out /Date(1390411800000)/ but want it formatted. Is it best to do in the jQuery after the success or in the C# when I return it? Whichever way, I'm not sure how to do it and could use some pointers.
Thanks!
It shows some red lines... do you want me to tell you what they say?
I'd say it's easiest to just do it in C# using ToString([time format]) with the proper format.
Since you have a DateTime? object, known as a Nullable<DateTime>, to access the DateTime value, you have to use the Value property of DateTime? (The Value property exists on all Nullable Types.
For "Jan 22, 14", the format would be as follows:
These are just some generic examples of the syntax:
// DateTime object
someDateTimeInstance.ToString("MMM d, yy");
// DateTime? object
someNullableDateTimeInstance.Value.ToString("MMM d, yy"); // assumes no nulls
// DateTime? object with null check
String formattedDateTime = (null != someNullableDateTimeInstance
? someNullableDateTimeInstance.Value.ToString("MMM d, yy")
: string.Empty);
Additionally, you're using Entity Framework which translates your LINQ statements into SQL.
Basically you have to pull the data first, and then format it. Even though CreateDateTime IS a Nullable<DateTime> column, that entire expression is converted by Linq-To-Entities to SQL. And, Linq-To-Entities doesn't know how to translate the method call .ToString(string format).
By separating the query from the format call, we avoid this issue. You get the data from the entities, and call .ToList() which will cause EF to load the data into memory. Then, you can work with this new list containing DateTime? objects and use the ToString(string format) method to get the formatted dates.
In your code:
[WebMethod]
public static object getBreadCrumbDate(int projectID, int statusID)
{
using (dbPSREntities5 myEntities = new dbPSREntities5())
{
var thisId = myEntities.tbBreadCrumbs.Where(x => x.ProjectID == projectID && x.StatusID == statusID).Max(x => x.BreadCrumbID);
var columns = myEntities.tbBreadCrumbs
.Where(x => x.BreadCrumbID == thisId)
.Select(x => x.CreateDateTime)
.ToList();
var formattedList = columns
.Select(d => null != d
? d.Value.ToString("MMM d, yy")
: string.Empty) // this is just one example to handle null
.ToList();
return formattedList;
}
}
if you can use datepicker then you could define a JavaScript function
getDateFromJson: function(jsonDateString, languageCode) {
return $.datepicker.formatDate($.datepicker.regional[languageCode].dateFormat, new Date(parseInt(jsonDateString.substr(6), 10)));
}
and then you could define a i18n file for the datepicker as
jQuery(function ($) {
$.datepicker.regional['en-us'] = {
closeText: 'Done',
prevText: 'Prev',
nextText: 'Next',
currentText: 'Today',
monthNames: ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'],
monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
dayNamesMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
weekHeader: 'Wk',
dateFormat: 'mm/dd/yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''
};
$.datepicker.setDefaults($.datepicker.regional['en-us']);
});
//German
jQuery(function($){
$.datepicker.regional['de'] = {
closeText: 'schließen',
prevText: '<zurück',
nextText: 'Vor>',
currentText: 'heute',
monthNames: ['Januar','Februar','März','April','Mai','Juni',
'Juli','August','September','Oktober','November','Dezember'],
monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun',
'Jul','Aug','Sep','Okt','Nov','Dez'],
dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
weekHeader: 'KW',
dateFormat: 'dd.mm.yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['de']);
});
So you could define your language and your dateFormat for it.
Now when you need a Date, just call this function
getDateFromJson(result.d[0], 'en-us'); //for USA Date
getDateFromJson(result.d[0], 'de'); //for German Date
Hope this points you in the right direction!