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

Posted

技术标签:

【中文标题】使用 Asp.Net MVC 和 KnockoutJS 处理日期【英文标题】:Handling dates with Asp.Net MVC and KnockoutJS 【发布时间】:2012-02-02 20:54:15 【问题描述】:

我最近开始使用 KnockoutJs 并很快意识到使用默认的 Json(myModelWithADate) 导致默认的 json 编码为 \/Date(-62135578800000)\/ 通过一些研究,我找到了四种可能的方法来处理我在 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.parse 处理您的日期,如 *** answer.

所示
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 日期选择器控件处理输入。

在处理显示日期或其他类型(例如货币)时,是否有公认的做法?是否还有其他选项可以解决这个问题?

【问题讨论】:

我在我的项目中使用字符串。模型绑定器可以从字符串中解析日期,因此我可以通过这种方式轻松地往返值。 我已将我的 json 净结果发布到相同的问题,它将日期转换为 iso 格式,使其更易于使用。 ***.com/questions/15778599/… 使用 momentjs 是处理日期的最佳方式,请参阅我对这个问题的回答。 【参考方案1】:

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

我已经切换到使用 JSON.NET 来处理我所有使用 JSON 的 ASP .NET 代码,因为它是一个更可定制的库。

例如,我必须在 MVC 中实现符合 Google's Chart API 的 JSON 数据(与 Knockout 结合用于分页等),而默认的 javascriptSerializer 根本无法做到。

除了使用 JSON.NET,您还可以对其进行自定义以实际输出完整的 Knockout 视图模型,因此您甚至不需要使用映射插件。

我编写了一个名为 FluentJson.NET 的示例库,它可以让您在 Razor 中执行以下操作:

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

得到:

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

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

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

【讨论】:

有趣的nuget项目,我一定会去看看的。 出于这个确切原因,我将 Json.Encode(Model) 替换为 JSON.NET JsonConvert.SerializeObject(Model)。像魅力一样工作,我不必编写任何其他代码行。很好的提示,我整天都在寻找这个。【参考方案2】:

我建议通过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 参数使您可以轻松地处理更改,并且也可以轻松地与数组一起使用。

【讨论】:

最佳解决方案:1- 无需将其他库添加到您的项目中。 2-您的代码不会遍历所有字段;它直接更新您指定的字段。这里只有一个问题是输入字段确实需要格式化字符串。【参考方案3】:

我正在使用以下代码生成短日期字符串。我将它用于我的日期字符串和 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""

这对我来说是干净的 JavaScript 代码。

【讨论】:

【参考方案4】:

刚刚提出这个问题是因为我们也开始在我们的 MVC3 应用程序上使用 knockout.js。 由于我们已经有了 jQuery datepicker,并且我们需要根据区域设置不同的日期格式(门户有不同的语言,并且每种语言呈现不同的格式),所以也许这种技术要求的混搭出现在其他地方并且会很有用:

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>

【讨论】:

【参考方案5】:

@photo_tom 的答案更简洁的替代方法是通过 JsonConverter 属性用 IsoDateTimeConverter 装饰属性,如下所示:

public class MyClass

    [JsonConverter(typeof(IsoDateTimeConverter))]
    public DateTime Timestamp  get; set; 

【讨论】:

【参考方案6】:

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

方法 1:直接在视图中:

假设您的淘汰模型在名为 sendDate 的可观察对象中获得了这样的日期,现在它的值是 /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 支持多种日期时间格式和日期实用函数。

【讨论】:

Tnx ajay,正是 js 拯救了我的一天,我喜欢 Approach 1 的简单方法【参考方案7】:

我喜欢 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);

【讨论】:

【参考方案8】:

我总是使用数据转换器而不是直接将数据发送到服务器来修复任何客户端编码或解析问题,而无需使用其他工具。

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

【讨论】:

以上是关于使用 Asp.Net MVC 和 KnockoutJS 处理日期的主要内容,如果未能解决你的问题,请参考以下文章

如何将 knockout.js 与 ASP.NET MVC ViewModels 一起使用?

检测 html table Knockout/ASP.NET MVC 中的选定行

如何在ASP.NET MVC5中正确包含jQuery与knockout.js

基于Bootstrap和Knockout.js的ASP.NET MVC开发实战 关于 拦截器的 学习 部分

使用asp.net mvc,boostrap及knockout.js开发微信自定义菜单编辑工具

建筑材料系统 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发