【问题标题】:Angular resource make date objects角度资源制作日期对象
【发布时间】:2014-02-02 11:08:58
【问题描述】:

我正在使用 $resource 来处理我的数据。我想在获取日期时将日期直接转换为日期对象。它只是让使用 datepicker 等变得更容易。

我的工厂:

AppFactories.factory("Books", ['$resource' ,function($resource){

  return $resource(
        "/books/:id",
        {id: "@id" },
        {
            "update": {method: "PUT", isArray: true },
            "save": {method: "POST", isArray: true },

        }
    );

}]);

我可以在工厂内创建一个函数,在我发布/更新时将数据库中的日期转换为日期对象,反之亦然?

将它直接集成到工厂中以便我可以重复使用它会非常好。

【问题讨论】:

    标签: javascript angularjs date


    【解决方案1】:

    您可以将其应用于底层 $http,而不是对每个资源都执行此操作,如更详细的描述 here

    app.config(["$httpProvider", function ($httpProvider) {
         $httpProvider.defaults.transformResponse.push(function(responseData){
            convertDateStringsToDates(responseData);
            return responseData;
        });
    }]);
    

    【讨论】:

    • 我使用了 Édouard Lopez 建议的 here 的正则表达式,而不是引用的博客文章中的正则表达式:/^([\+-]?\d{4}(?!\d{2} \b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?| W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d {2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?) [0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\ d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$ /
    • 这应该是一个公认的答案...它简单、优雅和通用!
    【解决方案2】:

    $resource 操作对象可以有一个名为 interceptor 的属性,它允许您为此特定操作 (like with $http interceptors) 定义一个 interceptor 对象。您可以为此拦截器定义responseresponseError 属性。这样您就可以为资源提供的操作定义一些日期解析功能:

    function parseResponseDates(response) {
      var data = response.data, key, value;
      for (key in data) {
        if (!data.hasOwnProperty(key) && // don't parse prototype or non-string props
            toString.call(data[key]) !== '[object String]') continue;
        value = Date.parse(data[key]); // try to parse to date
        if (value !== NaN) data[key] = value;
      }
      return response;
    }
    
    return $resource('/books/:id', {id: '@id'},
      {
        'update': {
          method: 'PUT', 
          isArray: true, 
          interceptor: {response: parseResponseDates}
        },
        ....
      }
    );
    

    希望这会有所帮助!

    【讨论】:

    • 您应该将“if (value !== NaN)”切换为“if(!isNaN(value))”。该行将始终评估为 false。
    【解决方案3】:

    我想使用 Angular.js 的 ngResource ($resource),但我也希望我的日期解析不会干扰 $http 中的任何其他内容,并且操作的 transformResponse 选项似乎比 interceptor 更合适选项。 @jakee 的 parseResponseDates 很好,因为它是通用的,但它比我想要的更暴力;我确切地知道模型中哪些字段可以是日期,我只想将这些字段解析为日期。

    文档说默认 transformResponse 只是 angular.fromJson 但这并不完全正确;它还会在运行angular.fromJson (http.js source reference) 之前去除JSON 漏洞保护前缀)]}',\n。由于$resource 不会轻易公开每个操作的transformResponse 数组,因此您必须手动处理扩展默认transformResponse,方法是注入$http,然后调用$http.defaults.transformResponse.concat(your_transformer)。在您的示例中,我得出的解决方案如下所示:

    AppFactories.factory("Books", function($resource, $http) {
      var raiseBook = function(book) {
        // "created_at" is declared as NOT NULL in the database
        book.created_at = new Date(book.created_at);
        // "completed_at" is a NULL-able field
        if (book.completed_at) {
          book.completed_at = new Date(book.completed_at);
        }
        return book;
      };
    
      var raiseBooks = function(books) {
        return books.map(raiseBook);
      };
    
      return $resource("/books/:id", {
        id: "@id"
      }, {
        update: {
          method: "PUT",
          isArray: true,
          // some_array.concat(...) creates and returns a new Array,
          //   without modifying the original some_array Array
          transformResponse: $http.defaults.transformResponse.concat(raiseBooks),
        },
        save: {
          method: "POST",
          isArray: true,
          transformResponse: $http.defaults.transformResponse.concat(raiseBooks),
        },
      });
    });
    

    请注意,Date.parse(...) 返回一个数字(自 UNIX 纪元以来的毫秒数),因此如果这是您想要的,则必须更改 new Date(...) 调用。但由于最初的问题需要日期对象,new Date(...) 可能是您想要的。

    【讨论】:

    • 感谢您的出色回答!值得注意的是,对于transformRequest,顺序可能是从角度 json 转换中受益的另一种方式,所以:transformRequest: [raiseBooks].concat($http.defaults.transformRequest)
    【解决方案4】:

    我采用了@chbrown 的回答并制作了角度服务,以便在我们需要在 ng-resource 请求/响应中即时透明地转换日期的任何情况下使用。

    这里是gist

    使用示例:

    var Session = $resource('/api/sessions/:id', {id: '@id'}, {
      query: {
        method: 'GET',
        isArray: true,
        transformResponse: dateTransformer.transformResponse.toDate(['start', 'end'])
      },
      update: {
        method: 'PUT',
        transformRequest: dateTransformer.transformRequest.toLocalIsoString(['start', 'end'])
      }
    });
    

    在返回的资源对象中的 Session.query() 字段 'start' 和 'end' 将是 JS Date 对象。 session.$update() 之后,服务器将接收 JSON,其中 JS Date 对象位于“start”和“end”字段中 将只是没有时区的 ISO 格式的字符串。

    支持的转换器:toDate、toLocalIsoString、toZonedIsoString。

    此服务使用 moment.js 进行日期解析和格式化,因为原生 JS Date 不支持 没有时区的日期(它们总是被解析为 UTC+0)。

    Lodash 也用于对象操作。

    【讨论】:

    • 最终使用了这个解决方案。这是最适合我的情况。不太宽泛(我确切地知道要被解析为日期的字段)并且应该具有低副作用。谢谢。哦,我不得不使用 DSpeichert 在链接要点上建议的第 77 行的修复:gist.github.com/xak2000/…
    • 我已将updatedgist 更新到最新版本。它现在可以与 Lodash 4.x 一起使用,并且具有更多功能。以前的版本设计用于 Lodash 3.x(这是第 77 行问题的原因)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 2016-05-10
    • 2020-05-14
    • 1970-01-01
    • 2014-12-09
    • 2017-07-19
    相关资源
    最近更新 更多