Manipulation des dates avec Asp.Net MVC et KnockoutJS

J'ai récemment commencé à travailler avec KnockoutJs et rapidement réalisé en utilisant le Json(myModelWithADate) par défaut Json(myModelWithADate) abouti à l'encodage json par défaut de \/Date(-62135578800000)\/ Avec un peu de recherche, j'ai localisé quatre manières possibles de gérer l'affichage de mes dates dans Éléments dom.

1) Créer une liaison qui gère la conversion de la date de Json au format que vous désirez

 ko.bindingHandlers.date = { init: function (element, valueAccessor, allBindingsAccessor, viewModel) { var jsonDate = valueAccessor(); var value = new Date(parseInt(jsonDate.substr(6))); var ret = value.getMonth() + 1 + "/" + value.getDate() + "/" + value.getFullYear(); element.innerHTML = ret; }, update: function(element, valueAccessor, allBindingsAccessor, viewModel) { } }; 

Usage

 <td data-bind="date: DueDate"> </td> 

2) Retourner "cordes" de votre contrôleur

 return Json(new {MyDate = DateTime.Now.ToShortDateString()}); 

3) Utilisez le JSON.NET pour spécifier un format Date Time vu à james.newtonking.com

Exemple

 string isoJson = JsonConvert.SerializeObject(entry, new IsoDateTimeConverter()); // {"Details":"Application started.","LogDate":"2009-02-15T00:00:00Z"} 

4) utilisez JSON.parse pour traiter vos dates comme indiqué dans cette réponse de stackoverflow.

 JSON.parse(jsonText, function(key, value) { // Check for the /Date(x)/ pattern var match = /\/Date\((\d+)\)\//.exec(value); if (match) { var date = new Date(+match[1]); // Convert the ticks to a Date object return humanReadable(date); // Format the date how you want it } // Not a date, so return the original value return value; }); 

Ils semblent tous fonctionner, mais je suis toujours en difficulté avec lequel on se sent "juste". En ce moment, mon intestin va avec un mélange avec les cordes de reliure et de retour. Comme je pouvais me voir étendre la liaison pour gérer l'entrée avec jQuery UI datepicker contrôles.

Existe-t-il une pratique acceptée lors de la gestion des dates d'affichage ou d'autres types tels que la monnaie? Existe-t-il une autre option qui me manque pour résoudre ce problème?

Personnellement, je pense que la solution JSON.NET est la meilleure simplement parce qu'elle impose moins au client. Toutes les autres solutions nécessitent un analyse complémentaire du client ou un code client supplémentaire.

J'ai changé pour utiliser JSON.NET pour tout mon code ASP .NET qui utilise JSON car c'est une bibliothèque beaucoup plus personnalisable.

Par exemple, j'ai dû implémenter des données JSON dans MVC conformes à Google Chart API (utilisé en combinaison avec Knockout pour la pagination, etc.) et le JavascriptSerializer par défaut ne peut tout simplement pas le faire.

En plus de JSON.NET, vous pouvez le personnaliser pour cracher complètement des modèles de vue Knockout complets, de sorte que vous n'avez même pas besoin d'utiliser le plugin de mappage.

J'ai écrit un exemple de bibliothèque appelé FluentJson.NET qui vous permet de faire des choses dans Razor comme:

 var viewModel = @JsonObject.Create() .AddProperty("name", "value") .AddObservable("knockoutProperty", 123) 

Et obtenir:

 var viewModel = {"name":"value","knockoutProperty":ko.observable(123)} 

Ainsi, vous pouvez obtenir un modèle de vue Knockout sans que des arcs latéraux du client puissent sauter.

Vous pourriez facilement étendre quelque chose comme ça pour gérer les valeurs de date, mais vous préféreriez.

Je suggérerais une approche intermédiaire par ko.mapping.fromJS( data, mapping ) cela vous permettra de personnaliser même avec un objet défini par l'utilisateur.

 var $data = { _ID : '1', _Created : someDate }; var $mapping = { '_Created' : { update: function (options) { return convertdata( options.data ); } } } var viewDataModel = ko.mapping( data, mapping ); ko.applyBindings( viewDataModel ); 

Le paramètre de mappage vous permet de gérer facilement les modifications et peut facilement être exploité avec des tableaux.

La meilleure façon de gérer les dates dans knockoutjs est d'utiliser la bibliothèque instantanée et de gérer des dates comme le patron. Vous pouvez facilement traiter des dates comme / Date (-62135578800000) /. Pas besoin de déranger la façon dont votre date de sérialisation dans le contrôleur.

Approche 1: Directement en vue:

Disons que votre modèle knock-out obtient une telle date dans un envoi envoyé par observable et maintenant il a valeur / Date (-62135578800000) /. Pour le lier en vue, vous pouvez le faire:

 <p><label>Date</label>: <span data-bind="moment(sentDate).format('MM/DD/YYYY')"></span></p> 

Approche 2: dans la liaison personnalisée

 ko.bindingHandlers.date = { init: function (element, valueAccessor, allBindingsAccessor, viewModel) { var jsonDate = valueAccessor(); var ret = moment(jsonDate).format('MM/DD/YYYY'); element.innerHTML = ret; }, update: function(element, valueAccessor, allBindingsAccessor, viewModel) { } }; 

Utilisation identique à celle que vous avez mentionnée:

 <td data-bind="date: sentDate"> </td> 

Momentjs prend en charge de nombreux formats de date et d'utilité sur les dates.

J'utilise le code suivant pour générer des chaînes de date courtes. Je l'utilise pour mes chaînes de dates et jQueryUi Date Picker.

 class T { public DateTime d { get; set; } } static void Main(string[] args) { var k = new T { d = DateTime.Now }; var formatter = new IsoDateTimeConverter(); formatter.DateTimeFormat = "d"; var s = JsonConvert.SerializeObject(k, formatter); } 

Cela génère le JSON suivant

 "{"d":"4/21/2012"}" 

Cela me donne un code JavaScript propre.

Je viens d'aborder cette question parce que nous avons également commencé à utiliser knockout.js sur notre application MVC3. Puisque nous avons déjà jQuery datepicker et nous devons formater les dates différemment par local (le portail a différentes langues et différents formats sont présentés par langue), donc peut-être que ce mélange d'exigences technologiques se produit quelque part et sera utile:

 var jsDateFormat = "@CultureHelper.JsDateFormat"; // can be something like yy-mm-dd //... ko.bindingHandlers.date = { init: function (element, valueAccessor, allBindingsAccessor, viewModel) { var value = valueAccessor(); if (value != null) { var jsonDate = new Date(parseInt(valueAccessor().substr(6))); element.innerHTML = jQuery.datepicker.formatDate(jsDateFormat, jsonDate); } }, update: function (element, valueAccessor, allBindingsAccessor, viewModel) { } }; 

Et dans la vue, par exemple:

 <p><label>Date</label>: <span data-bind="date: SentDate"></span></p> 

Une alternative plus propre à la réponse @ photo_tom est de décorer la propriété avec IsoDateTimeConverter via l'attribut JsonConverter, de la manière suivante:

 public class MyClass { [JsonConverter(typeof(IsoDateTimeConverter))] public DateTime Timestamp { get; set; } } 

J'ai adoré la réponse d'Andres Toro, sauf que dans mon cas, les champs de saisie attendent des chaînes formatées. Je suis donc en train d'utiliser JQuery pour formater mes dates en fonction de mon format favori fourni par mon helper @Html.ConvertDateFormat() J'espère que ça aide quelqu'un.

 var mapping = { 'ActualDateTime': { update: function (options) { var d = /\/Date\((\d*)\)\//.exec(options.data); return (d) ? $.datepicker.formatDate('@Html.ConvertDateFormat()', new Date(+d[1])) : value; //return "5/10/2017"; } } }; var paymentModel = ko.mapping.fromJS(modelJSON, mapping);