標籤:
所謂的選擇聯動,就是指,當我DateTimePicker1選擇2月4號的時候,我DateTimePicker2隻能選擇2月4號和2月5號兩天,當然你可以自行規定要選擇的日期。這在一些圖表查詢條件裡面是很常用的一個功能。下面我們就來看看如何設計。
DateTimePicker的選取與使用
在這裡,我們使用的DateTimePicker是一個開源的組件,他的model名稱為:ui.bootstrap.datetimepicker,我們可以去這個網址找到其相關的內容:http://dalelotts.github.io/angular-bootstrap-datetimepicker/,然後下載其相應的包,最後放到項目中,並進行引用即可(注意不能少了moment.js,它是構建與這個組件的基礎上):
<!--DateTimePicker Part--> <link href="~/Content/front/angular-datetimepicker/css/datetimepicker.css" rel="stylesheet" /> <script src="~/Content/front/angular-datetimepicker/js/moment.js"></script> <script src="~/Content/front/angular-datetimepicker/js/zh-cn.js"></script> <script src="~/Content/front/angular-datetimepicker/js/datetimepicker.js"></script>
然後在module中進行註冊:
var app = angular.module(‘dsBootstrap‘, [ ‘ui.grid‘, ‘ui.grid.selection‘, ‘ui.grid.pagination‘, ‘ngCookies‘, ‘ui.bootstrap.datetimepicker‘ ]);
最後在HTML頁面進行排版布局使用即可:
<div class="row" ng-show="visible"> <div class="col-md-4"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">開始時間:</span> <div class="dropdown"> <a class="dropdown-toggle" id="starttime" role="button" data-toggle="dropdown" data-target="#" href="#"> <div class="input-group"> <input type="text" class="form-control" data-ng-model="starttime|date:‘yyyy-MM-dd‘ "><span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span> </div> </a> <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"> <datetimepicker data-ng-model="starttime" data-on-set-time="onTimeSet(newDate, oldDate)" data-datetimepicker-config="{ dropdownSelector: ‘#starttime‘,startView:‘day‘, minView:‘day‘ }" /> </ul> </div> </div> </div> <div class="col-md-4"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">結束時間:</span> <div class="dropdown"> <a class="dropdown-toggle" id="endtime" role="button" data-toggle="dropdown" data-target="#" href="#"> <div class="input-group"> <input type="text" class="form-control" data-ng-model="endtime|date:‘yyyy-MM-dd‘ "><span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span> </div> </a> <ul class="dropdown-menu" id="endContainer" role="menu" aria-labelledby="dLabel"> </ul> </div> </div> </div> </div>
這樣我們就完成了第一步的工作了。從上面的Html代碼我們可以看出,starttime和endtime是傳遞到controller中的所選擇的日期值。而且我們的endtime DateTimePicker我們並沒有放到前台,我們需要在後台動態產生。為什麼呢?因為我們需要根據StartTime的選取值,來計算出endTime的選取範圍,所以這裡需要動態產生綁定。
DateTimePicker的聯動
下面我們開始設計其聯動工作。
首先,當選擇開始時間後,會進入onTimeSet事件,在這個事件中,我們先動態產生結束時間選取器:
$scope.onTimeSet = function (newDate, oldDate) { var startTimeFmt = moment($scope.starttime).format("YYYY-MM-DD"); var endTimeFmt = moment(startTimeFmt).add(1, ‘day‘).format("YYYY-MM-DD"); //時間框置空 $("#endtime input").val(""); //移除原有的datetimepicker對象 $("#endContainer").children().remove(); //設定config $scope.config = { dropdownSelector: "#endtime", startView: "day", minView: "day" }; //動態編譯datetimepicker directive var compiledeHTML = $compile(‘<datetimepicker data-ng-model="endtime" data-before-render="beforeRender($view, $dates, $leftDate, $upDate, $rightDate)" data-datetimepicker-config="{{config}}" />‘)($scope); //放入html容器 $("#endContainer").append(compiledeHTML); }
然後,當上面的方法執行到$compile的時候,就會觸發其beforeRender事件,此事件允許在控制項載入前,進行一些相關操作。我們利用這個事件,拋出一個days-check事件,以便動態載入時間範圍:
//當選擇開始時間,會進入onTimeSet事件,執行到$compile的時候,就會觸發下面的beforeRender事件 //觸發beforeReder事件後,會拋出一個days-check事件出去,並附帶所有的當頁時間對象。 $scope.beforeRender = function ($view, $dates, $leftDate, $upDate, $rightDate) { $timeout(function () { $scope.$broadcast(‘days-check‘, $dates); }); }
最後,我們接收這個事件:
//接收事件,並重設頁面 $scope.$on(‘days-check‘, function (e, d) { for (var i = 0; i < d.length; i++) { //初始設定為不可選狀態,不選中狀態 d[i].active = false; d[i].selectable = false; //當前loop的值 var currentDate = moment(d[i].utcDateValue).format("YYYY-MM-DD"); //當前選定的開始時間 var startTimeFmt = moment($scope.starttime).format("YYYY-MM-DD"); //允許選定的最大的結束時間 var endTimeFmt = moment(startTimeFmt).add(1, ‘day‘).format("YYYY-MM-DD"); //比較並設定可選日期 if (currentDate >= startTimeFmt && currentDate <= endTimeFmt) { d[i].selectable = true; } } });
當我們收到這個days-check事件的時候,我們會首先重設所有日期為不可選狀態,然後根據預先設定的值,來確定選取範圍。 這樣,通過上面的設定,我們的結束時間就能根據開始時間的選擇而進行聯動了。是不是很方便呢?最後附上controller總體代碼:
app.controller(‘collectorController‘, [‘$scope‘, ‘$cookies‘, ‘$timeout‘,‘$compile‘, ‘baseService‘, ‘collectorService‘, ‘uiGridConstants‘, function ($scope, $cookies,$timeout,$compile, baseService, collectorService, uiGridConstants) { var self = this; $scope.ProvinceData = null; $scope.CityData = null; $scope.DistrictData = null; $scope.CompanyData = null; $scope.MachineData = null; $scope.RealTimeData = null; $scope.HistoryData = null; $scope.selectedProvince = null; $scope.selectedCity = null; $scope.selectedDistrict = null; $scope.selectedCompany = null; $scope.selectedMachine = null; $scope.starttime = null; $scope.endtime = null; $scope.visible = false; //datetimepicker是否顯示 //art.dialog({ title: ‘載入提示‘, icon: ‘face-smile‘, fixed: true,left:‘50%‘,top:0, time:3, content: "日期選擇跨度不要過大,否則會因為資料量過大而無法載入圖表和列表!", padding: 0 }); //監測省份的變化,如果發生了變化,則載入城市列表 $scope.$watchCollection(‘selectedProvince‘, function (oldval, newval) { $scope.GetCityList(); }); //監測城市變化,如果發生了變化,則載入地區列表 $scope.$watchCollection(‘selectedCity‘, function (oldval, newval) { $scope.GetDistrictList(); }); //監測地區變化,如果發生了變化,則載入公司列表 $scope.$watchCollection(‘selectedDistrict‘, function (oldval, newval) { $scope.GetCompanyList(); }); //監測公司變化,如果發生了變化,則載入機器列表 $scope.$watchCollection(‘selectedCompany‘, function (oldval, newval) { $scope.GetMachineList(); }); //繫結資料行表 $scope.gridOptions = { enableRowSelection: true, enableSelectAll: false, selectionRowHeaderWidth: 35, rowHeight: 35, showGridFooter: false, multiSelect: true, enablePaginationControls: true, paginationPageSizes: [9, 15, 20], paginationPageSize: 9 }; $scope.gridOptions.columnDefs = [{ name: ‘Param_name‘, displayName: ‘參數名稱‘ },{ name: ‘Param_unit‘, displayName: ‘參數單位‘ }, { name: ‘Param_data‘, displayName: ‘參數值‘ }, { name: ‘Param_time‘, displayName: ‘採集時間‘ } ]; $scope.gridOptions.onRegisterApi = function (gridApi) { $scope.gridApi = gridApi; }; //省份綁定 collectorService.GetProvinceData().then(function (data) { var flag = data.data.success; if (flag) { $scope.ProvinceData = data.data.data; $scope.selectedProvince = baseService.getSelectedDataMapper($scope.ProvinceData, ‘province‘); } }, null); $scope.GetCityList = function () { var selectedProvinceId; if ($scope.selectedProvince != undefined) selectedProvinceId = $scope.selectedProvince.id; else return; //市區綁定 collectorService.GetCityData(selectedProvinceId).then(function (data) { var flag = data.data.success; if (flag) { $scope.CityData = data.data.data; $scope.selectedCity = baseService.getSelectedDataMapper($scope.CityData, ‘city‘); } }, null); } $scope.GetDistrictList = function () { var selectedCityId; if ($scope.selectedCity != undefined) selectedCityId = $scope.selectedCity.id; else return; //區縣綁定 collectorService.GetDistrictData(selectedCityId).then(function (data) { var flag = data.data.success; if (flag) { $scope.DistrictData = data.data.data; $scope.selectedDistrict = baseService.getSelectedDataMapper($scope.DistrictData, ‘district‘); } }, null); } $scope.GetCompanyList = function () { var selectedDistrictId; if ($scope.selectedDistrict != undefined) selectedDistrictId = $scope.selectedDistrict.id; else return; //公司綁定 collectorService.GetCompanyData(selectedDistrictId).then(function (data) { var flag = data.data.success; if (flag) { $scope.CompanyData = data.data.data; $scope.selectedCompany = baseService.getSelectedDataMapper($scope.CompanyData, ‘company‘); } }, null); } $scope.GetMachineList = function () { var selectedCompanyId; if ($scope.selectedCompany != undefined) selectedCompanyId = $scope.selectedCompany.id; else return; //裝置綁定 collectorService.GetMachineList(selectedCompanyId).then(function (data) { var flag = data.data.success; if (flag) { $scope.MachineData = data.data.data; $scope.selectedMachine = baseService.getSelectedDataMapper($scope.MachineData, ‘machine‘); } }, null); } //擷取即時資料 $scope.GetRealTimeDataByMachine = function () { timeCheck($scope.starttime, $scope.endtime); var starttimeFmt = timeFmt($scope.starttime); var endtimeFmt = timeFmt($scope.endtime); //擷取即時資料 var machineId = $scope.selectedMachine.machine_id; collectorService.GetRealDataList(machineId).then(function (data) { var flag = data.data.success; if (flag) { $scope.RealTimeData = data.data.data; } }, null); //擷取列表資料 collectorService.GetHistoryDataList(machineId,starttimeFmt,endtimeFmt).then(function (data) { var flag = data.data.success; if(flag) { $scope.HistoryData = data.data.data; $scope.gridOptions.data = data.data.list; } }, null); //將級聯清單項目放到cookie中,以便於之後的操作簡易化 var expireDate = new Date(); expireDate.setDate(expireDate.getDate() + 7); delete $cookies[‘frontselection‘]; var cookieData = JSON.stringify({ province: $scope.selectedProvince, city: $scope.selectedCity, district: $scope.selectedDistrict, company: $scope.selectedCompany, machine: $scope.selectedMachine }); $cookies.put(‘frontselection‘, cookieData, { ‘expires‘: expireDate }); } $scope.ClickToGetParamDataList = function (paramId) { timeCheck($scope.starttime,$scope.endtime); var starttimeFmt = timeFmt($scope.starttime); var endtimeFmt = timeFmt($scope.endtime); var machineId = $scope.selectedMachine.machine_id; collectorService.GetHistoryDataListByParamId(machineId, paramId, starttimeFmt, endtimeFmt).then(function (data) { var flag = data.data.success; if (flag) { $scope.gridOptions.data = data.data.list; } }); } //顯示隱藏時間段選擇 $scope.ClickToShowTimePicker = function () { $scope.visible = !$scope.visible; } $scope.onTimeSet = function (newDate, oldDate) { var startTimeFmt = moment($scope.starttime).format("YYYY-MM-DD"); var endTimeFmt = moment(startTimeFmt).add(1, ‘day‘).format("YYYY-MM-DD"); //時間框置空 $("#endtime input").val(""); //移除原有的datetimepicker對象 $("#endContainer").children().remove(); //設定config $scope.config = { dropdownSelector: "#endtime", startView: "day", minView: "day" }; //動態編譯datetimepicker directive var compiledeHTML = $compile(‘<datetimepicker data-ng-model="endtime" data-before-render="beforeRender($view, $dates, $leftDate, $upDate, $rightDate)" data-datetimepicker-config="{{config}}" />‘)($scope); //放入html容器 $("#endContainer").append(compiledeHTML); } //接收事件,並重設頁面 $scope.$on(‘days-check‘, function (e, d) { for (var i = 0; i < d.length; i++) { //初始設定為不可選狀態,不選中狀態 d[i].active = false; d[i].selectable = false; //當前loop的值 var currentDate = moment(d[i].utcDateValue).format("YYYY-MM-DD"); //當前選定的開始時間 var startTimeFmt = moment($scope.starttime).format("YYYY-MM-DD"); //允許選定的最大的結束時間 var endTimeFmt = moment(startTimeFmt).add(1, ‘day‘).format("YYYY-MM-DD"); //比較並設定可選日期 if (currentDate >= startTimeFmt && currentDate <= endTimeFmt) { d[i].selectable = true; } } }); //當選擇開始時間,會進入onTimeSet事件,執行到$compile的時候,就會觸發下面的beforeRender事件 //觸發beforeReder事件後,會拋出一個days-check事件出去,並附帶所有的當頁時間對象。 $scope.beforeRender = function ($view, $dates, $leftDate, $upDate, $rightDate) { $timeout(function () { $scope.$broadcast(‘days-check‘, $dates); }); } var timeCheck = function(start,end) { if (start == null && end!=null) { art.dialog({ title: ‘提示‘, icon: ‘error‘, time: 6, content: "必須選擇開始日期,請重試!", padding: 0 }); return; } if (start!=null && end == null) { art.dialog({ title: ‘提示‘, icon: ‘error‘, time: 6, content: "必須選擇結束日期,請重試!", padding: 0 }); return; } if (start != null && end != null && start > end) { art.dialog({ title: ‘提示‘, icon: ‘error‘, time: 6, content: "開始時間不能大於結束時間,請重試!", padding: 0 }); return; } } var timeFmt = function(time) { if (time == null) time = ""; else time = time.toLocaleDateString(); return time; }}]);
物聯網平台設計心得:DateTimePicker實現選擇聯動