2

As part of an ASP.NET MVC4 Web Application, I have a client-side Javascript Viewmodel with a "Save" function that POSTs to a controller:

PatientViewModel = function (data) {
    var self = this;
    ko.mapping.fromJS(data, {}, self);

    self.save = function () {
        $.ajax({
            url: "/Patient/Save/",
            type: "POST",
            data: ko.toJSON(self),
            contentType: "application/json",
            success: function (data) {
                if (data.patientViewModel != null) {                 
                    ko.mapping.fromJS(data.patientViewModel, {}, self);
                }
            }
        });
    }
}

Upon "success", the client expects data that contains the original viewmodel that is re-mapped using KnockoutJS. The following server-side viewmodel is the blueprint for the mapping:

public class PatientViewModel
    {
        public int PatientId { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public DateTime? DOB { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Zip { get; set; }
        public string Phone { get; set; }
        public string PhoneAlternate { get; set; }
    }

Notice the DOB property with a type of DateTime?. This is set on the client along with all the other properties.

The controller that receives the viewmodel from the client creates a new "Patient" that is saved to a database.

        public JsonResult Save(PatientViewModel patientViewModel)
        {
            Patient patient = new Patient();

            patient.LastName = patientViewModel.LastName;
            patient.FirstName = patientViewModel.FirstName;
            patient.DOB = patientViewModel.DOB;
            patient.Address = patientViewModel.Address;
            patient.City = patientViewModel.City;
            patient.State = patientViewModel.State;
            patient.Zip = patientViewModel.Zip;
            patient.Phone = patientViewModel.Phone;
            patient.PhoneAlternate = patientViewModel.PhoneAlternate;

            _patientContext.Patients.Add(patient);
            _patientContext.SaveChanges();

            return Json(new { patientViewModel });
        }

When the controller returns its "JsonResult", the result contains the original viewmodel with the DOB (DateTime?) property set to "Now" instead of the date and time it received from the client.

The other properties remain the same as when the viewmodel was originally sent to the controller. I've debugged and stepped through the code. The DOB property holds the date sent to it at the point of return Json(new {patientViewModel} );, and changes to "Now" as soon as it hits the success method in the client-side viewmodel.

What am I missing?

  • Could you show the constructor to PatentViewModel ? – Luc Morin Oct 16 '15 at 15:01
  • In your controller in the Save method, does the date of birth field bind back in the patientViewModel correctly? Is the issue just when you save to the database the new patient? – Chad Oct 16 '15 at 15:14
  • There currently is no constructor for PatientViewModel. A viewmodel object is created just before the client-side view is accessed (PatientViewModel pm = new PatientViewModel();) – Michael Ingersoll Oct 16 '15 at 15:17
  • 1
    curious ! why you want to pass the same model your received from client(ajax) . you have all the updated data in client vm for further use , no need to do this again under success `ko.mapping.fromJS(data.patientViewModel, {}, self);`. help me understand if something is the case – super cool Oct 16 '15 at 15:18
  • @Chad Fortunately there is no issue regarding the database. The Patient object is created and saved successfully. My curiosity is when I put a "debugger" line in the client-side viewmodel just before the "if (data.patientViewModel != null)" statement, the DOB property shows "/Date(-268171200000)/". This translates to today's date. The date from the client was 12/25/1983 (random date I picked). I would think this wouldn't be a binding issue since the ko.mapping statement hasn't been reached at that point. Of course, I could be wrong. – Michael Ingersoll Oct 16 '15 at 15:29
  • This link may help: http://everythingjs.blogspot.com/2012/03/json-dates-and-knockoutjs-date-binding.html It explains the weird formatting that JSON does to Date objects. – Chad Oct 16 '15 at 15:42
  • @supercool The "success" function will eventually have multiple purposes. The JsonResult returned from the controller may contain a url for a redirect, for example. Also I may include other properties in the viewmodel that are altered on the server side. Therefore I would need to re-mapp on the client. – Michael Ingersoll Oct 16 '15 at 15:45
  • @BlueMentat `/Date(-268171200000)/` can not translate to today's date. It should be something before 1970 i guess. – Dandy Oct 16 '15 at 18:00
  • 1
    @BlueMentat Maybe you should try Network tab in browser developer tools. You can see there response for your request. It will tell if problems are on server or in client. – Valyok26 Oct 16 '15 at 20:01

1 Answers1

0

Thanks to everyone who gave comments and suggestions to my question.

In the end, it turns out that the DateTime property on my viewmodel was not being set to "Now"; it was being reset when the client side recieved it.

Why was it being reset? Because Microsoft's Json() method that I use to re-serialize my viewmodel does not return a ISO8601 formated Date Object. This is the format the client expected, so it did the best it could (which was a reset).

The Stackoverflow post ASP.NET MVC JsonResult Date Format gives a further explanation on this issue as well as a solution.

I added JSON.NET to my application (bypassing Microsoft's Json method) and changed the Save method of my controller:

public ContentResult Save(PatientViewModel patientViewModel)
        {
            Patient patient = new Patient();

                              .
                              .
                              .

            string patVM = JsonConvert.SerializeObject(new { patientViewModel });

            return new ContentResult { Content = patVM, ContentType = "application/json" };

        }

The date now populates the appropriate property. Once again, thanks!

Community
  • 1
  • 1