所谓的选择联动,就是指,当我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; } }]); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· 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 让容器管理更轻松!