所謂的選擇聯動,就是指,當我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;
}
}]);
