2015-11-10 18 views
6

我採用了棱角分明的UI引導日期選擇器時: https://angular-ui.github.io/bootstrap/#/datepicker解析日期字符串Date對象加載UI角引導日期選擇器

當使用從服務器接收到的數據我呈現的形式,有一個與日期時間字段問題。我輸入日期選擇器看起來是這樣的:

<form name="itemForm"> 
    <input type="datetime" class="form-control" id="startedAt" name="startedAt" 
      ng-model="item.startedAt" 
      ng-click="open($event, 'startedAt')" 
      uib-datepicker-popup="yyyy-MM-dd" 
      is-open="datepickers.startedAt" 
    /> 
</form> 

我的服務器返回的響應日期時間爲JSON字符串:

{  
    ... 
    startedAt: "2015-05-29T02:00:00+0200" 
} 

當我給你響應數據模型$scope.item = response;,日期選擇器輸入字段被正確地渲染(正確的日期是選中它並按我選擇的格式正確格式化)。問題是驗證不通過。我得到:

itemForm.startedAt.$invalid == true 

我注意到,綁定到日期選擇現場數據應該是Date對象,而不是字符串(當我選擇從日期選擇新的日期,$scope.item.startedAtDate

我設法解決這個問題,併爲此在控制器:

$scope.item = response; 
$scope.item.startedAt = new Date($scope.item.startedAt); 

是這樣工作的。但我不希望手動轉換字符串做的日期我都能收到服務器的響應時間。我試圖創建一個指令,我可以分配到日期選擇器輸入字段,以便將其轉換爲我ng-model

.directive("asDate", function() { 
    return { 
     require: 'ngModel', 
     link: function (scope, element, attrs, modelCtrl) { 

      modelCtrl.$formatters.push(function (input) { 

       var transformedInput = new Date(input); 

       if (transformedInput != input) { 
        modelCtrl.$setViewValue(transformedInput); 
        modelCtrl.$render(); 
       } 

       return transformedInput; 
      }); 
     } 
    } 
}) 

那麼它的作品,因爲現在我可以看到在我看來Date對象,當我輸出模式:{{item.startedAt}}。但仍然驗證失敗!我懷疑這是我理解數據如何在模型和視圖之間流動以及UI Bootstrap如何掛鉤的問題。

而且當我改變我的指令從$formatters.push$formatters.unshift,審定工程確定,但日期選擇不格式化我的日期時間(insted的的很好formattet yyyy-MM-dd我看到裏面輸入ISO字符串)

+1

噢人! –

+0

@VictorParmar目前我正在這樣做 - 從服務器接收時將響應字符串轉換爲Date對象。並且在發送到服務器時將Date對象轉換爲字符串。所有這些都是在Angular controller中手動完成的。也許我只是將這個邏輯提取爲Angular服務,但我認爲它不可能與指令 – rsobon

+2

一起加入俱樂部 - 我們最終也做了同樣的事情:)當您使用JavaScript for-in循環時,您可能會遇到同樣的問題: –

回答

1

由於這是故意的使用angular-ui-bootstrap datepicker(https://github.com/angular-ui/bootstrap/issues/4690)的行爲,我最終使用了Angular service/factory和moment庫。

服務dateConverter可以全局注入來攔截所有的HTTP請求/響應或僅在所需的控制器中。

這裏我使用Restangular庫來處理對REST API的請求,因此response.plain()方法只採用對象屬性,而不採用Restangular方法/屬性。

var Services = angular.module('app.Services', []); 

Services 
    .factory('dateConverter', ['dateFilter', function (dateFilter) { 

     var dateConverter = {}; 

     dateConverter.prepareResponse = function (response) { 
      for(prop in response.plain()) { 
       if (response.hasOwnProperty(prop)) { 
        if(moment(response[prop], moment.ISO_8601, true).isValid()) { 
         response[prop] = new Date(response[prop]); 
        } 
       } 
      } 
      return response; 
     }; 

     dateConverter.prepareRequest = function (item) { 
      for(prop in item.plain()) { 
       if (item.hasOwnProperty(prop)) { 
        if(angular.isDate(item[prop])){ 
         item[prop] = dateFilter(item[prop] , "yyyy-MM-ddTHH:mm:ssZ") 
        } 
       } 
      } 
      return item; 
     }; 

     return dateConverter; 
    }]) 
; 
0

這打破了作爲角。 UI.Bootstrap v0.13.2(8-2-2015) 降級到0.13.1作品,這是我今天被卡住的地方。

Wesleycho說,這是故意做 https://github.com/angular-ui/bootstrap/issues/4690

我已經準備好支持串其他日期選擇器,如果任何人有什麼建議

...很快發佈此後,我去了一個非角我不是很自豪的路徑,但它適用於HTML5 type =「date」和uib-datepicker-popup。我有一個正則表達式,用於確定字符串是否類似於我所見過的兩種序列化日期格式之一,然後我有一個遞歸JavaScript函數來遍歷json樹並用Date()替換那些字符串。您可以在放入$ scope(或viewmodel)之前調用它...

$http.get("../api/comm/" + commId 
    ).success(function (resp) { 
     fixDates(resp); 
     vm.comm = resp; 
    }); 

(我不需要檢查字符串的長度,但我想它會通過不運行正則表達式騰出一些CPU週期,如果字符串顯然不是一個日期)

//2015-10-01T00:00:00-04:00 
//2015-11-20T18:15:56.6229516-05:00 
var isDate = new RegExp("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{7})?-\\d{2}:00"); 

function fixDates(json) { 
    for (i in json) 
     if (typeof (json[i]) == "object") 
      fixDates(json[i]); 
     else if (typeof (json[i]) == "string" && (json[i].length == 25 || json[i].length == 33) && isDate.test(json[i])) 
      json[i] = new Date(json[i]); 
}; 
+0

還應該使用hasOwnProperty() – rsobon

0

您可以將字符串日期在restangular變壓器,像我們這裏有完全相同的問題這

RestangularConfigurer 
    .addElementTransformer('<RESTRESOURCENAME>', false, function (element) { 
     element.createDate = new Date(element.createDate); 
     return element; 
    })