随笔 - 394  文章 - 0  评论 - 946  阅读 - 143万 

所谓的选择联动,就是指,当我DateTimePicker1选择2月4号的时候,我DateTimePicker2只能选择2月4号和2月5号两天,当然你可以自行规定要选择的日期。这在一些图表查询条件里面是很常用的一个功能。下面我们就来看看如何设计。

DateTimePicker的选取与使用

在这里,我们使用的DateTimePicker是一个开源的组件,他的model名称为:ui.bootstrap.datetimepicker,我们可以去这个网址找到其相关的内容:http://dalelotts.github.io/angular-bootstrap-datetimepicker/,然后下载其相应的包,最后放到项目中,并进行引用即可(注意不能少了moment.js,它是构建与这个组件的基础上):

1
2
3
4
5
<!--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中进行注册:

1
2
3
4
5
6
7
var app = angular.module('dsBootstrap', [
                                        'ui.grid',
                                        'ui.grid.selection',
                                        'ui.grid.pagination',
                                        'ngCookies',
                                        'ui.bootstrap.datetimepicker'
                                        ]);

最后在HTML页面进行排版布局使用即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<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事件,在这个事件中,我们先动态生成结束时间选择器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$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事件,以便动态加载时间范围:

1
2
3
4
5
6
7
//当选择开始时间,会进入onTimeSet事件,执行到$compile的时候,就会触发下面的beforeRender事件
//触发beforeReder事件后,会抛出一个days-check事件出去,并附带所有的当页时间对象。
$scope.beforeRender = function ($view, $dates, $leftDate, $upDate, $rightDate) {
    $timeout(function () {
        $scope.$broadcast('days-check', $dates);
    });
}

最后,我们接收这个事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//接收事件,并重置页面
$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总体代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
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;
    }
}]);
posted on   程序诗人  阅读(2059)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示