javascript - Manejo de fechas con Asp.Net MVC y KnockoutJS
asp.net-mvc json (7)
Recientemente comencé a trabajar con KnockoutJs y rápidamente me di cuenta de que el uso de Json(myModelWithADate)
predeterminado Json(myModelWithADate)
daba como resultado la codificación json predeterminada de //Date(-62135578800000)//
Con un poco de investigación //Date(-62135578800000)//
cuatro formas posibles de manejar la visualización de mis fechas en elementos dom
1) Cree un enlace que maneje la conversión de la fecha Json al formato que desee
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) {
}
};
Uso
<td data-bind="date: DueDate">
</td>
2) Devuelve "strings" de tu Controlador
return Json(new {MyDate = DateTime.Now.ToShortDateString()});
3) Use JSON.NET para especificar un formato de fecha y hora visto en james.newtonking.com
Ejemplo
string isoJson = JsonConvert.SerializeObject(entry, new IsoDateTimeConverter());
// {"Details":"Application started.","LogDate":"2009-02-15T00:00:00Z"}
4) usa JSON.parse para manejar tus fechas como se ve en esta respuesta 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;
});
Todos parecen funcionar, pero todavía estoy luchando con cuál se siente "bien". En este momento, mi intestino va con una mezcla con las cuerdas de unión y de retorno. Como pude ver, extendí el enlace para manejar la entrada con los controles jQuery UI datepicker.
¿Existe una práctica aceptada cuando se manejan fechas de visualización u otros tipos como la moneda? ¿Hay alguna otra opción que me falta que resuelva este problema?
Estoy usando el siguiente código para generar cadenas de fecha cortas. Lo uso para mis cadenas de fechas y 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);
}
Esto genera el siguiente JSON
"{"d":"4/21/2012"}"
Esto resulta en un código JavaScript limpio para mí.
La mejor forma de manejar las fechas en knockoutjs es usar la biblioteca de momentos y manejar fechas como boss. Puede tratar fácilmente con fechas como / Fecha (-62135578800000) /. No es necesario molestarse en cómo serializar la fecha en el controlador.
Enfoque 1: Directamente a la vista:
Digamos que su modelo knockout obtiene esa fecha en un observable llamado sentDate y ahora tiene valor / Fecha (-62135578800000) /. Para enlazarlo a la vista puede hacer:
<p><label>Date</label>: <span data-bind="moment(sentDate).format(''MM/DD/YYYY'')"></span></p>
Enfoque 2: En enlace personalizado
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) {
}
};
Uso igual que usted había dicho:
<td data-bind="date: sentDate">
</td>
momentjs admite muchos formatos de fecha y hora y funciones de utilidad en fechas.
Me encantó la respuesta de Andrés Toro, excepto que en mi caso, los campos de entrada esperan cadenas formateadas. Así que estoy usando JQuery para formatear mis fechas de acuerdo con mi formato favorito provisto por mi ayudante @Html.ConvertDateFormat()
Espero que esto ayude a alguien el día.
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);
Personalmente creo que la solución JSON.NET es la mejor simplemente porque impone menos en el cliente. Todas las demás soluciones requieren un análisis adicional del cliente o un código de cliente adicional.
He cambiado a usar JSON.NET para todo mi código ASP .NET que usa JSON porque es una biblioteca mucho más personalizable.
Por ejemplo, tuve que implementar datos JSON en MVC que se ajustaban a la API Chart de Google (utilizada en combinación con Knockout para paginación, etc.) y el JavascriptSerializer
predeterminado simplemente no puede hacerlo.
Además, con JSON.NET, puede personalizarlo para que escuche modelos de vista completa Knockout así que ni siquiera necesita emplear el plugin de mapeo.
Escribí una biblioteca de muestra llamada FluentJson.NET que te permite hacer cosas en Razor como:
var viewModel = @JsonObject.Create()
.AddProperty("name", "value")
.AddObservable("knockoutProperty", 123)
Y obten:
var viewModel = {"name":"value","knockoutProperty":ko.observable(123)}
Así que puedes obtener un modelo de vista Knockout sin ningún tipo de aros en el lado del cliente para saltar.
Podría extender fácilmente algo así para manejar los valores de fecha como prefiera.
Solo se me ocurrió esta pregunta porque también comenzamos a utilizar knockout.js en nuestra aplicación MVC3. Como ya tenemos jQuery datepicker y tenemos que formatear las fechas de manera diferente según la configuración regional (el portal tiene diferentes idiomas y se presentan diferentes formatos por idioma), tal vez esta combinación de requisitos tecnológicos surja en otro lugar y sea útil:
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) {
}
};
Y en la vista, por ejemplo:
<p><label>Date</label>: <span data-bind="date: SentDate"></span></p>
Una alternativa más limpia a la respuesta de @ photo_tom es decorar la propiedad con IsoDateTimeConverter a través del atributo JsonConverter, así:
public class MyClass
{
[JsonConverter(typeof(IsoDateTimeConverter))]
public DateTime Timestamp { get; set; }
}
Yo sugeriría un enfoque de intermediario a través de ko.mapping.fromJS( data, mapping )
esto le permitiría personalizar incluso con un objeto definido por el usuario.
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 );
el parámetro de mapeo le permite manejar cambios fácilmente y también puede ser aprovechado fácilmente con arreglos.