用Asp处理日期.. Net MVC和KnockoutJS

Handling dates with Asp.Net MVC and KnockoutJS

本文关键字:MVC KnockoutJS Net 日期 Asp 处理      更新时间:2023-09-26

我最近开始使用KnockoutJs,并很快意识到使用默认的Json(myModelWithADate)导致'/Date(-62135578800000)'/的默认json编码。经过一些研究,我找到了四种潜在的方法来处理在dom元素中显示日期。

1)创建一个绑定,处理从Json日期到所需格式的转换

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) {
    }
};
使用

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

2)从控制器返回"字符串"

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

3)使用JSON。. NET指定日期时间格式见james.newtonking.com

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

4)使用JSON。解析处理你的日期,就像在这个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;
});

它们似乎都有效,但我仍在纠结哪一个感觉"正确"。现在我的直觉是结合绑定和返回字符串。正如我所看到的那样,我扩展了绑定,以便用jQuery UI datepicker控件处理输入。

在处理显示日期或其他类型(如货币)时,是否存在可接受的实践?是否还有其他选项可以解决这个问题?

我个人认为JSON。. NET解决方案是最好的,因为它对客户端的影响较小。所有其他解决方案都需要额外的客户端解析或额外的客户端代码。

我已经切换到使用JSON。对于我所有使用JSON的asp.net代码,因为它是一个更可定制的库。

例如,我必须在MVC中实现JSON数据,符合谷歌的图表API(与Knockout结合使用,用于分页等),默认的JavascriptSerializer根本无法做到这一点。

除了JSON。你可以自定义它,让它实际吐出完整的Knockout视图模型,这样你甚至不需要使用映射插件。

我写了一个名为FluentJson的样例库。. NET允许你在Razor中做如下事情:
var viewModel = @JsonObject.Create()
    .AddProperty("name", "value")
    .AddObservable("knockoutProperty", 123)

,得到:

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

因此,您可以获得一个Knockout视图模型,而无需跳过任何客户端环节。

你可以很容易地扩展这样的东西来处理你喜欢的日期值

我建议通过ko.mapping.fromJS( data, mapping )使用中间人方法,这将允许您使用用户定义的对象进行自定义。

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 );

mapping参数允许您轻松地处理更改,也可以轻松地利用数组。

在knockoutjs中处理日期的更好方法是使用moment库并像boss一样处理日期。您可以轻松处理/Date(-62135578800000)/之类的日期。不需要关心如何在控制器中序列化日期。

方法1:直接在视图中:

假设你的knockout模型在一个名为sentDate的可观察对象中获得这样的日期,现在它的值为/date(-62135578800000)/。要在视图中绑定它,你可以这样做:

<p><label>Date</label>: <span data-bind="moment(sentDate).format('MM/DD/YYYY')"></span></p>
方法2:自定义绑定
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) {
    }
};

用法和你刚才说的一样:

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

momentjs支持大量的日期时间格式和实用程序函数的日期

我使用以下代码生成短日期字符串。我将它用于日期字符串和jQueryUi日期选择器。

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);
    }

生成以下JSON

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

刚刚出现这个问题,因为我们也开始在我们的MVC3应用程序中使用knockout.js。因为我们已经有了jQuery datepicker,我们需要根据地区(门户有不同的语言,每种语言都有不同的格式)对日期进行不同的格式化,所以这种技术需求的mashup可能会在其他地方出现,并且会很有用:

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) {
    }
};

然后在视图中例如:

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

对于@photo_tom的答案,一个更简洁的替代方案是通过JsonConverter属性用IsoDateTimeConverter来装饰该属性,如下所示:

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

我喜欢Andres Toro的回答,只是在我的情况下,输入字段期望格式化字符串。所以我使用JQuery来格式化我的日期根据我的助手@Html.ConvertDateFormat()提供的我最喜欢的格式希望有一天能帮到别人。

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);

我总是使用数据转换器而不是直接向服务器发送数据来修复任何客户机编码或解析问题,而不需要使用额外的工具。

在Knockout JS视图模型文件中,我在视图模型设置之前添加了以下代码,它拦截视图模型的选定属性,并使用moment.js处理日期转换:

// converting data before sending to controller
var dataConverter = function (key, value) {  
    if (key === 'InvoiceDate') {
        return moment(value).format("YYYY MMMM DD");
    }
    return value;
};

然后我在视图模型中的ajax保存方法中使用dataConverter而不是data:

// Example view model for sales invoice
SalesInvoiceViewModel = function (data) {
    var self = this;
    ko.mapping.fromJS(data, {}, self);
    self.SaveInvoice = function () {
        $.ajax({
            url: '/SalesInvoices/SaveInvoice/',
            type: 'POST',
            data: ko.toJSON(self, **dataConverter**),
            contentType: 'application/json',
            success: function (data) {
                if (data.invoiceViewModel !== null) {
                    ko.mapping.fromJS(data.invoiceViewModel, {}, self);
                }
                if (data.redirectToLocation !== null) {
                    window.location = data.redirectToLocation;
                }
            },
            error: function (xhr, ajaxOptions, thrownError) {
                // report error to user
            }
        });
    }