標籤:
在設計物聯網平台的時候,涉及到一個五級聯動的問題,操作順序如下:依次選擇 所屬省份,所屬市縣,所屬地區,所屬公司,裝置名稱。在使用Jquery時代,做好這個其實很容易,但是稍顯繁瑣,並且得很好的處理上一級下拉式清單選中,然後觸發下一級下拉式清單載入資料的問題。相比使用Angularjs而言,代碼量大而且繁瑣,並且還得處理好順序載入的問題。本節我們就看看Angularjs能給我們帶來怎麼樣的體驗吧。本文成文倉促,講解難免會有謬誤,還請見諒。
五級聯動的設計
由於省份,市縣,地區,公司四張表,在資料庫中的設計基本一致,我們就專門為這四種下拉式清單設計一個公用的模板出來。
app.directive(‘sectorPart‘, [function() { return { restrict: ‘AE‘, replace: true, scope: { options: "=" }, template: ‘<select class="form-control" ng-options="item as item.name for item in options" name="state" style="width:220px;height:33px;">‘ + ‘<option value="">請選擇</option>‘ + ‘</select>‘ };}]);
由於裝置表中的資料欄位類型不太一致,所以這裡我們專門為裝置設計一種下拉式清單模板:
app.directive(‘sectorMachine‘, [function () { return { restrict: ‘AE‘, replace: true, scope: { options: "=" }, template: ‘<select class="form-control" ng-options="item as item.machine_name for item in options" name="state" style="width:220px;height:33px;">‘ + ‘<option value="">請選擇</option>‘ + ‘</select>‘ };}]);
好了,模板都設計完畢了,我們接下來將模板(Directive)應用到頁面中:
<div class="searchcontainer"> <div class="row"> <div class="col-md-4"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">所屬省份:</span> <sector-part options="ProvinceData" ng-model="selectedProvince" ng-change="GetCityList()"></sector-part> </div> </div> <div class="col-md-4"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">所屬市縣:</span> <sector-part options="CityData" ng-model="selectedCity" ng-change="GetDistrictList()"></sector-part> </div> </div> <div class="col-md-4"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">所屬地區:</span> <sector-part options="DistrictData" ng-model="selectedDistrict" ng-change="GetCompanyList()"></sector-part> </div> </div> </div> <div class="row"> <div class="col-md-4"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">所屬公司:</span> <sector-part options="CompanyData" ng-model="selectedCompany" ng-change="GetMachineList()"></sector-part> </div> </div> <div class="col-md-4"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">裝置名稱:</span> <sector-machine options="MachineData" ng-model="selectedMachine" ng-change="RefreshPage()"></sector-machine> </div> </div> <div class="col-md-4"> <div class="input-group"> <button class="btn btn-success" ng-click="LoadControllerList()" style="height:33px;line-height:16px;width:315px;">點擊載入</button> </div> </div> </div> </div>
從HTML模板中,我們可以看到以下幾個關鍵點:options是我傳入到下拉式清單的資料,下拉式清單會根據options的值來載入列表並顯示;ng-model是我選中的項,一旦有列表被選中,就會將資料傳遞到這個model中;ng-change是下拉式清單被選中的時候觸發的事件。
最後讓我們來看看Controller中的寫法吧:
app.controller(‘collectorController‘, [‘$scope‘, ‘$cookies‘, ‘$timeout‘,‘$compile‘, ‘baseService‘, ‘collectorService‘, ‘uiGridConstants‘, function ($scope, $cookies,$timeout,$compile, baseService, collectorService, uiGridConstants) { var self = this; $scope.selectedProvince = null; $scope.selectedCity = null; $scope.selectedDistrict = null; $scope.selectedCompany = null; $scope.selectedMachine = null; //省份綁定 collectorService.GetProvinceData().then(function (data) { var flag = data.data.success; if (flag) { $scope.ProvinceData = data.data.data; } }, 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; } }, 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; } }, null); } $scope.GetCompanyList = function () { var selectedDistrictId; if ($scope.selectedDistrict != undefined) else return; //公司綁定 collectorService.GetCompanyData(selectedDistrictId).then(function (data) { var flag = data.data.success; if (flag) { $scope.CompanyData = data.data.data; } }, 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; } }, null); }}]);
看上去是不是挺簡潔的。反正這些方法的觸發都是根據ng-change來進行的。然後ng-model由於是mvvm模式,所以一旦選中項改變,會自動被傳到controller中來。至於collectorService就是一個簡單的擷取資料的service而已,這裡不是主要的,我簡單的貼一下:
app.service(‘collectorService‘, [‘$http‘, function ($http) { var provinceData = function () { return $http({ method: ‘POST‘, url: ‘/Process/GetLocationList?provinceid=-1&cityid=-1‘ }); } var cityData = function (provinceId) { return $http({ method: ‘POST‘, url: ‘/Process/GetLocationList?provinceid=‘ + provinceId + ‘&cityid=-1‘ }); } var districtData = function (cityId) { return $http({ method: ‘POST‘, url: ‘/Process/GetLocationList?provinceid=-1&cityid=‘ + cityId }); } var companyData = function (districtId) { return $http({ method: ‘POST‘, url: ‘/BaseData/GetSchoolByDistrictId?districtId=‘ + districtId }); } var machineList = function (companyId) { return $http({ method: ‘POST‘, url: ‘/Machine/GetMachineBy?companyId=‘ + companyId + ‘&isController=0‘ }); } return { GetProvinceData: provinceData, GetCityData: cityData, GetDistrictData: districtData, GetCompanyData: companyData, GetMachineList: machineList };}]);
好了,以上就是五級聯動了。我們可以一級一級的點下去了。是不是很方便呢?操作圖展示:
五級聯動記憶恢複
在實際使用的時候,有的使用者反映,五級聯動選擇很麻煩,需要一個一個的點,如果能記憶上次的選擇項就好了。這樣就可以不用費力的每次都點擊了。基於此種使用者需求,我決定利用cookie來記憶使用者上次的選擇內容,然後在下次瀏覽的時候,來載入之前的瀏覽記錄。下面我們來分析一下如何能夠做到自動的根據已有記錄逐級載入下來列表並選中。
首先,我們需要將資料儲存到cookie中。
其次,我們需要監視列表選項的變化,這裡我們可以用$watchcollection方法。
最後,列表選項變化後,我們就需要依據選中內容,載入下級列表,所以這裡我們需要多selectedProvice,selectedCity等變數賦值。
明白了這些步驟,下面我們進行改造:
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.$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(); }); //省份綁定 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 () { //將級聯清單項目放到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 }); }}]);
可以看出,我們在點擊最後的載入按鈕的時候,把cookie儲存到了瀏覽器中。然後在頁面進入的時候,我們先載入了省份列表,省份列表載入成功後,我們馬上從cookie中拿出上次選中的省份,然後給selectedProvice賦值,這個賦值動作會馬上觸發$watchcollection中的動作,然後進行市縣的綁定。一級一級的觸發,直到最後。
有人會問,那個baseService是幹什麼的。由於我將$scope.selectedProvince,$scope.selectedCity等對象直接儲存到了cookie中,在取出來的時候,我發現這些entity已經變了,entity內部會自動多出來一個_hashcode的屬性,導致和原來的entity有差別,這就會導致angularjs無法通過驗證,我必須通過baseService的方法,來還原出原來的selectedProvice等對象才行。
app.service(‘baseService‘, [‘$cookies‘, function ($cookies) { //擷取比對資料並賦值 //type: province,city,district,company,machine var selectionMapper = function (sourceData, type) { //從cookie擷取值 var collectorSelectionFromCookie = $cookies.get(‘frontselection‘); if (collectorSelectionFromCookie != undefined) { //如果cookie存在,則進行解析 collectorSelectionFromCookie = JSON.parse($cookies.get(‘frontselection‘)); for (var i = 0; i < sourceData.length; i++) { var current = sourceData[i]; if (type == "province") { if (current.id == collectorSelectionFromCookie.province.id) { return current; } } if (type == "city") { if (current.id == collectorSelectionFromCookie.city.id) { return current; } } if (type == "district") { if (current.id == collectorSelectionFromCookie.district.id) { return current; } } if (type == "company") { if (current.id == collectorSelectionFromCookie.company.id) { return current; } } if (type == "machine") { if (current.machine_id == collectorSelectionFromCookie.machine.machine_id) { return current; } } if (type == "monitor") { if (current.id == collectorSelectionFromCookie.monitor.id) { return current; } } } } return null; } return { getSelectedDataMapper: selectionMapper };}]);
最後我們開啟頁面,看看載入的結果吧:
物聯網平台設計心得:五級聯動及記憶恢複