MVC JSON AJAX DateTime Format - ajax

Hi I am trying to use AJAX to edit a grid.
First I made model (BPViewModel):
public DateTime Day { get; set; }
The Repository:
public static IList<BPViewModel> All()
{
IList<BPViewModel> result = (IList<BPViewModel>)HttpContext.Current.Session["BloodPressures"];
// string id = "2222222222";
// id = Session["PHN"].ToString();
if (result == null)
{
HttpContext.Current.Session["BloodPressures"] = result =
(from bloodpressure in new DALDataContext().BloodPressures
select new BPViewModel
{
.......
Day = bloodpressure.Day
}).ToList();
}
return result;
}
In the controller I get the data using"
public ActionResult BloodPressure_Read([DataSourceRequest] DataSourceRequest request)
{
return Json(BPRepository.All().ToDataSourceResult(request));
}
In the view:
#(Html.Kendo().Grid<BPViewModel>()
.Name("Grid")
.Columns(columns =>
columns.Bound(p => p.Day).Format("{0:d}");
The date is displayed as 1/1/2012; however when I edit it (using Ajax) it shows as Sun Jan 1 00:00:00 PST 2012!! When I try to update the row, I get "Day is invalid Date.
I tried to use bloodpressure.Day.ToShortDateString(), it did not work.
Any idea how I can convert the date to yyyy,mm,dd?
Thanks in advance.

For reference, here is some reading material on MSDN for date time formatting: http://msdn.microsoft.com/en-us/library/8kb3ddd4
That said have you tried something as simple as the following:
yourdate.ToString("yyyy-MM-dd");

Related

Conversion between IEnumerable EnumerableRowCollection

I have the following code:
var aaData = myapi.GetData().AsEnumerable().Select(x => new {
Id = x["myID"],
Desc = x["myDesc"]
});
Trying to do the following
aaData = aaData.OrderBy((string.Join(",", request.Order
.Select(x => request.Columns[x.Column].Data + " " + x.Dir))));
Getting error:
CS0266 Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<>' to 'System.Data.EnumerableRowCollection<>'. An explicit conversion exists (are you missing a cast?)
How to fix this?
GetData returns a DataTable
Request is an object having a property:
public OrderCol[] Order { get; set; }
OrderCol is
public class OrderCol {
public int Column { get; set; }
public string Dir { get; set; }
}
Thanks for your assistance.
The above code works for the case when I get a List<> back instead of DataTable. The error states that a Cast is needed and it seems to be how DataTable.AsEnumerable is set up as a EnumerableRowCollection
Can use a mock datatable to mimic the above
DataTable dt = new DataTable();
dt.clear();
dt.Columns.Add("myID");
dt.Columns.Add("myDesc");
all i needed was to convert to a list and things worked fine

DateTime format in MVC controller Edit Action

I have a Create view that allows a user to add Title and Date. When the user goes to edit it should show the Title and Date when it was created. I'm not sure how to do this.
[HttpGet]
public IActionResult Edit(int id)
{
var iDate = DateTime.Now.ToString("MM/dd/yyyy HH:mm");
var editViewModel = new CreateEditViewModel
{
Id = id,
AsOf = ToEdit.AsOf,
Title = ToEdit.Title,
)
};
editViewModel.AsOf = DateTime.ParseExact(iDate, "MM/dd/yyyy
HH:mm", null);
return View(editViewModel);
}
I am currently using DateTime.Now in the Edit Action in the controller but I know this isn't correct because it was show the current date/time insted of the date and time that it was originally created.
Are you getting the model to edit from a database?

How to pass a parameter to the Read method of signalr transport for Kendo UI grid data source

I was looking at the demo:
Telerik's Demo
and this
Telerik's Example
I still cannot figure out how, using this technique, to pass a parameter
to the Read method, so instead of reading ALL games or products, it reads ONLY a
subset of games or products, by category ID lest say. If I change the Read method in
the server-side code to take a parameter, it never gets hit anymore,
and I cannot figure out how to pass a parameter from the transport
client-side definition definition... Any help would be highly
appreciated!
I posted the question to the Telerik's forums and got this which should work!
Telerik's Answer
In case anyone else comes along in the future and the link in the other answer is gone, or for those who don't want to download a project file and sift through it themselves, here's more detail from the answer given on the Telerik forums:
They use Kendo.DynamicLinq to "bind the request parameters."
They created a custom class that mirrors the structure of the existing DataSourceRequest class typically used in AJAX grid actions.
using System.Collections.Generic;
using Kendo.DynamicLinq;
namespace SignalRLocalHub.Models
{
public class MyDataSourceRequest
{
public int Take { get; set; }
public int Skip { get; set; }
public int Page { get; set; }
public int PageSize { get; set; }
public Filter Filter { get; set; }
public IEnumerable<Sort> Sort { get; set; }
public IEnumerable<Aggregator> Aggregates { get; set; }
}
}
In the ProductHub (SignalR hub) class, this is the Read method:
public DataSourceResult Read(MyDataSourceRequest request)
{
return productService.Read()
.ToDataSourceResult(
request.Take,
request.Skip,
request.Sort,
request.Filter,
request.Aggregates);
}
The productService.Read method it calls, for reference, looks like this:
//int take, int skip, IEnumerable<Sort> sort, Filter filter, IEnumerable<Aggregator> aggregates
public IQueryable<ProductViewModel> Read()
{
return entities.Products
.OrderBy(p => p.ProductID)
.Select(product => new ProductViewModel
{
ProductID = product.ProductID,
ProductName = product.ProductName,
UnitPrice = product.UnitPrice.HasValue ? product.UnitPrice.Value : default(decimal),
UnitsInStock = product.UnitsInStock.HasValue ? product.UnitsInStock.Value : default(short),
Discontinued = product.Discontinued
});
}
And finally, here is the grid's DataSource configuration:
.DataSource(d => d
.SignalR()
.AutoSync(true)
.Transport(tr => tr
.Promise("hubStart")
.Hub("hub")
.Client(c => c.Read("read").Create("create").Update("update").Destroy("destroy"))
.Server(s => s.Read("read").Create("create").Update("update").Destroy("destroy"))
)
.ServerFiltering(true)
.Filter(f => f.Add(m => m.UnitPrice).IsEqualTo(10))
.ServerPaging(true)
.PageSize(10)
.Schema(s => s
.Data("Data")
.Total("Total")
.Aggregates("Aggregates")
.Model(m =>
{
m.Id(e => e.ProductID);
m.Field(e => e.ProductID).Editable(false);
})
)
)
This allows sorting, paging, and filtering by any field that is part of the grid view model. So as long as your "category ID" is a property of the grid view model and the grid is configured to be able to filter by that field, this method should work.

ASP.NET MVC - Preserving invalid DateTime selection with 3 dropdown lists

I'm still fairly new to ASP.NET and MVC and despite days of googling and experimenting, I'm drawing a blank on the best way to solve this problem.
I wrote a BirthdayAttribute that I want to work similar to the EmailAddressAttribute. The birthday attribute sets the UI hint so that the birthday DateTime will be rendered using an editor template that has 3 dropdown lists. The attribute can also be used to set some additional meta data that tells the year dropdown how many years it should display.
I know I could use jQuery's date picker, but in the case of a birthday I find the 3 dropdowns much more usable.
#model DateTime
#using System;
#using System.Web.Mvc;
#{
UInt16 numberOfVisibleYears = 100;
if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("NumberOfVisibleYears"))
{
numberOfVisibleYears = Convert.ToUInt16(ViewData.ModelMetadata.AdditionalValues["NumberOfVisibleYears"]);
}
var now = DateTime.Now;
var years = Enumerable.Range(0, numberOfVisibleYears).Select(x => new SelectListItem { Value = (now.Year - x).ToString(), Text = (now.Year - x).ToString() });
var months = Enumerable.Range(1, 12).Select(x => new SelectListItem{ Text = new DateTime( now.Year, x, 1).ToString("MMMM"), Value = x.ToString() });
var days = Enumerable.Range(1, 31).Select(x => new SelectListItem { Value = x.ToString("00"), Text = x.ToString() });
}
#Html.DropDownList("Year", years, "<Year>") /
#Html.DropDownList("Month", months, "<Month>") /
#Html.DropDownList("Day", days, "<Day>")
I also have a ModelBinder to rebuild my date afterwards. I've removed the content of my helper functions for brevity, but everything works great up to this point. Normal, valid dates, work just fine for creating or editing my members.
public class DateSelector_DropdownListBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (bindingContext == null)
throw new ArgumentNullException("bindingContext");
if (IsDropdownListBound(bindingContext))
{
int year = GetData(bindingContext, "Year");
int month = GetData(bindingContext, "Month");
int day = GetData(bindingContext, "Day");
DateTime result;
if (!DateTime.TryParse(string.Format("{0}/{1}/{2}", year, month, day), out result))
{
//TODO: SOMETHING MORE USEFUL???
bindingContext.ModelState.AddModelError("", string.Format("Not a valid date."));
}
return result;
}
else
{
return base.BindModel(controllerContext, bindingContext);
}
}
private int GetData(ModelBindingContext bindingContext, string propertyName)
{
// parse the int using the correct value provider
}
private bool IsDropdownListBound(ModelBindingContext bindingContext)
{
//check model meta data UI hint for above editor template
}
}
Now that I'm looking at it, I should probably be using a nullable DateTime, but that's neither here nor there.
The problem I'm having is with very basic validation of invalid dates such as February 30th, or September 31st. The validation itself works great, but the invalid dates aren't ever saved and persisted when the form is reloaded.
What I'd like is to remember the invalid date of February 30th and redisplay it with the validation message instead of resetting the dropdowns to their default value. Other fields, like the email address (decorated with the EmailAddressAttribute) preserve invalid entries just fine out of the box.
At the moment I am just trying to get the server side validation working. To be honest, I haven't even started thinking about the client side validation yet.
I know there is lots I could do with javascript and ajax to make this problem a moot point, but I would still rather have the proper server side validation in place to fall back on.
I finally managed to solve my problem, so I wanted to share my solution.
DISCLAIMER:
Although I used to be great with .NET 2.0 back in the day, I'm only now updating my skills to the latest versions of C#, ASP.NET, MVC, and Entity Framework. If there are better ways to do anything I've done below please I'm always open to feedback.
TODO:
Implement client side validation for invalid dates such as February 30th. Client side validation for [Required] attribute is already built in.
Add support for cultures so that the date shows up in desired format
The solution came to me when I realized that the problem I was having is that DateTime will not allow itself to be constructed with an invalid date such as February 30th. It simply throws an exception. If my date wouldn't construct, I knew of no way to pass my invalid data back through the binder to the ViewModel.
To solve this problem, I had to do away with the DateTime in my view model and replace it with my own custom Date class. The solution below will provide fully functioning server side validation in the event that Javascript is disabled. In the event of a validation error the invalid selections will persist after the validation message is displayed allowing the user to easily fix their mistake.
It should be easy enough to map this view-ish Date class to the DateTime in your date model.
Date.cs
public class Date
{
public Date() : this( System.DateTime.MinValue ) {}
public Date(DateTime date)
{
Year = date.Year;
Month = date.Month;
Day = date.Day;
}
[Required]
public int Year { get; set; }
[Required, Range(1, 12)]
public int Month { get; set; }
[Required, Range(1, 31)]
public int Day { get; set; }
public DateTime? DateTime
{
get
{
DateTime date;
if (!System.DateTime.TryParseExact(string.Format("{0}/{1}/{2}", Year, Month, Day), "yyyy/M/d", CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
return null;
else
return date;
}
}
}
This is just a basic date class that you can construct from a DateTime. The class has properties for Year, Month, and Day as well as a DateTime getter that can try to retrieve you a DateTime class assuming you have a valid date. Otherwise it returns null.
When the built in DefaultModelBinder is mapping your form back to this Date object, it will take care of the Required and Range validation for you. However, we will need a new ValidationAtribute to make sure that invalid dates such as February 30th aren't allowed.
DateValidationAttribute.cs
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public sealed class DateValidationAttribute : ValidationAttribute
{
public DateValidationAttribute(string classKey, string resourceKey) :
base(HttpContext.GetGlobalResourceObject(classKey, resourceKey).ToString()) { }
public override bool IsValid(object value)
{
bool result = false;
if (value == null)
throw new ArgumentNullException("value");
Date toValidate = value as Date;
if (toValidate == null)
throw new ArgumentException("value is an invalid or is an unexpected type");
//DateTime returns null when date cannot be constructed
if (toValidate.DateTime != null)
{
result = (toValidate.DateTime != DateTime.MinValue) && (toValidate.DateTime != DateTime.MaxValue);
}
return result;
}
}
This is a ValidationAttribute that you can put on your Date fields and properties. If you pass in the resource file class and the resource key it will search the corresponding resource file in your "App_GlobalResources" folder for the error message.
Inside the IsValid method, once we're sure we're validating a Date we check it's DateTime property to see if it's not null to confirm that it's valid. I throw in a check for DateTime.MinValue and MaxValue for good measure.
So that's about it really. With this Date class, I managed to do away completely with the custom ModelBinder. This solution relies completely on the DefaultModelBinder, which means all of the validation works right out of the box. It apparently even checks my new DateValidationAttribute, which I was super excited about. I stressed forever thinking I might have to muck with validators in a custom binder. This feels a lot cleaner.
Here is the complete code for the partial view I'm using.
DateSelector_DropdownList.cshtml
#model Date
#{
UInt16 numberOfVisibleYears = 100;
if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("NumberOfVisibleYears"))
{
numberOfVisibleYears = Convert.ToUInt16(ViewData.ModelMetadata.AdditionalValues["NumberOfVisibleYears"]);
}
var now = DateTime.Now;
var years = Enumerable.Range(0, numberOfVisibleYears).Select(x => new SelectListItem { Value = (now.Year - x).ToString(), Text = (now.Year - x).ToString() });
var months = Enumerable.Range(1, 12).Select(x => new SelectListItem { Text = new DateTime(now.Year, x, 1).ToString("MMMM"), Value = x.ToString() });
var days = Enumerable.Range(1, 31).Select(x => new SelectListItem { Value = x.ToString(), Text = x.ToString() });
}
#Html.DropDownList("Year", years, "<Year>") /
#Html.DropDownList("Month", months, "<Month>") /
#Html.DropDownList("Day", days, "<Day>")
I'll also include the attribute I use that sets up the template hint and the number of visible years to show.
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public sealed class DateSelector_DropdownListAttribute : DataTypeAttribute, IMetadataAware
{
public DateSelector_DropdownListAttribute() : base(DataType.Date) { }
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues.Add("NumberOfVisibleYears", NumberOfVisibleYears);
metadata.TemplateHint = TemplateHint;
}
public string TemplateHint { get; set; }
public int NumberOfVisibleYears { get; set; }
}
I think the solution turned out a lot cleaner than I expected it to. It solves all of my problems in the exact way that I was hoping to. I do wish that I was somehow able to keep the DateTime, but this is the only way I could figure out how to maintain an invalid selection using only server side code.
Are there any improvements you would make?

ASP.NET MVC change model data type in before send to view

I used Linq to Entity, for fetch a model from DB
var works = db.Work.Where(a => a.StartDate == DateTime.Now).ToList();
this model contain a DateTime that I want to change it to string before send it to view
beacuase need to show it as a persianDate Time,
like this :
foreach (var item in workslist)
{
item.StartDate = "1391/01/01"; //Just For Exapmle as you know this won't work
}
return View(workslist);
So is there any way to change a data type in a strongly typed model? or other way to do this except save DateTime as String in my DB
You can use the [DisplayFormat] attribute with EditorFor/DisplayFor helpers to format the data.
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy/mm/dd}")]
public DateTime StartDate { get; set; }
Then in view:
#Html.EditorFor(m => m.StartDate)
OR, you can also consider to define separate ViewModel for your 'Work' domain model. Though this approach results in more code, it's provide more flexibility and considered as good practice.
Here is sample code:
public class Work
{
public DateTime StartDate {get;set;}
}
public class WorkViewModel
{
public WorkViewModel()
{
}
public string StartDate { get; set; }
public static WorkViewModel Map(Work domainModel)
{
return new WorkViewModel() {
//Apply your Date format logic
StartDate = domainModel.StartDate.ToString("yyyy/MM/dd")
};
}
}
In action method:
var works = db.Work.Where(a => a.StartDate == DateTime.Now).ToList();
var workViewModels = new List<WorkViewModel>(works.Count);
foreach (var work in works)
workViewModels.Add(WorkViewModel.Map(work));
return View(workViewModels);
you can have a function in your controller to change datetime to string
public string changeDateTimeToPersianString ( DateTime time)
{
// your code
}
then you can call this function from your View.
in Razor something like this
#changeDateTimeToPersianString(workslistitem.StartDate)

Resources