物聯網平臺設計心得:五級聯動及記憶恢復

在設計物聯網平臺的時候,涉及到一個五級聯動的問題,操做順序以下:依次選擇 所屬省份,所屬市縣,所屬地區,所屬公司,設備名稱。在使用Jquery時代,作好這個其實很容易,可是稍顯繁瑣,而且得很好的處理上一級下拉列表選中,而後觸發下一級下拉列表加載數據的問題。相比使用Angularjs而言,代碼量大並且繁瑣,而且還得處理好順序加載的問題。本節咱們就看看Angularjs能給咱們帶來怎麼樣的體驗吧。本文成文倉促,講解不免會有謬誤,還請見諒。html

五級聯動的設計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)應用到頁面中:cookie

  <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是下拉列表被選中的時候觸發的事件。app

最後讓咱們來看看Controller中的寫法吧:less

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而已,這裏不是主要的,我簡單的貼一下:mvvm

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
    };
}]);

好了,以上就是五級聯動了。咱們能夠一級一級的點下去了。是否是很方便呢?操做圖展現:ui

QQ截圖20160221195706

五級聯動記憶恢復this

在實際使用的時候,有的用戶反映,五級聯動選擇很麻煩,須要一個一個的點,若是能記憶上次的選擇項就行了。這樣就能夠不用費力的每次都點擊了。基於此種用戶需求,我決定利用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
    };
}]);

最後咱們打開頁面,看看加載的結果吧:

QQ截圖20160221201230

相關文章
相關標籤/搜索