当配置选项来自service时,Angular中的控件会中断

Controls in Angular break when configuration options come from service

本文关键字:Angular 控件 中断 选项 配置 service      更新时间:2023-09-26

我有一个服务,将返回我的一些配置选项的ng-grid。getGridOptions函数以使用它的控制器的名称为参数,并返回正确的选项集(为了简单起见,这里只显示了一个)。

ng-grid选项服务:

angular.module('services').service('GridOptionsService',function(){
    var documents = {
        data: 'myData',
        enablePaging: true,
        showFooter:true,
        totalServerItems: 'totalServerItems',
        pagingOptions: {
            pageSizes: [50,100,200],
            pageSize: 50,
            currentPage: 1
        },
        filterOptions:  {
            filterText: '',
            useExternalFilter: false
        },
        enableCellEdit: false,
        enableColumnReordering: true,
        enablePinning: false,
        showGroupPanel: false,
        groupsCollapsedByDefault: true,
        enableColumnResize: true,
        showSelectionCheckbox: true,
        selectWithCheckboxOnly: true,
        columnDefs: [
            {field:'docId', displayName:'Document ID', cellTemplate: NgGridDomUtil.toLink('#/documents/{{row.getProperty(col.field)}}')},
            {field:'docTags', displayName:'Tags'},
            {field:'lastSaveDate', displayName:'Last saved'},
            {field:'documentVersion', displayName:'Version', width: 120},
            {field:'busDocId', displayName:'Customer Doc ID'},
            {field:'markedForDelete', displayName:'Deleted', width: 120, cellTemplate: NgGridDomUtil.toCheckbox('{{row.getProperty(col.field)}}')}]
    };
    var gridOptionManager = {
        documents: documents
    }
    return {
        getGridOptions: function(controllerName){
            return gridOptionManager[controllerName];
        }
    }
})

NgGridDomUtil类只是让它更容易在网格上设置样式:

var NgGridDomUtil = (function(){
    var toLink = function(href){
    var html = '<div class="ngCellText" ng-class="col.colIndex()"><a ng-href= "'+href+'" class="ngCellLink"><span ng-cell-text>{{row.getProperty(col.field)}}</span></a></div>'
    return html;
}
var toCheckbox = function(_selected){
    var html = '<div class="ngCellText" ng-class="col.colIndex()"><input type="checkbox" ng-change="console.log('+"TEST"+')" ng-model="COL_FIELD"  ng-input="COL_FIELD"' + (_selected ? 'selected' : '') + ' /></div>'
    return html
}
return {
    toLink: toLink,
    toCheckbox: toCheckbox
}
})();

我的问题是,当我使用GridOptionsService检索数据时,数据仍然正确地呈现给网格,但文本过滤不再工作,分页被破坏。然而,selectedFilterOption仍然工作。

控制器:

angular.module('controllers').controller('Repository', ['$scope', 'DataContext','GridOptionsService','$http', function($scope, DataContext,GridOptionsService,$http) {
    $scope.filterOptions = {
        filterText: '',
        useExternalFilter: false
    };
    $scope.totalServerItems =0;
    $scope.pagingOptions ={
        pageSizes: [5,10,100],
        pageSize: 5,
        currentPage: 1
    }
    //filter!
    $scope.dropdownOptions = [{
        name: 'Show all'
    },{
        name: 'Show active'
    },{
        name: 'Show trash'
    }];
    //default choice for filtering is 'show active'
    $scope.selectedFilterOption = $scope.dropdownOptions[1];

    //three stage bool filter
    $scope.customFilter = function(data){
        var tempData = [];
        angular.forEach(data,function(item){
            if($scope.selectedFilterOption.name === 'Show all'){
                tempData.push(item);
            }
            else if($scope.selectedFilterOption.name ==='Show active' && !item.markedForDelete){
                tempData.push(item);
            }
            else if($scope.selectedFilterOption.name ==='Show trash' && item.markedForDelete){
                tempData.push(item);
            }
        });
        return tempData;
    }

    //grabbing data
    $scope.getPagedDataAsync = function(pageSize, page,  searchText){
        var data;
        if(searchText){
            var ft = searchText.toLowerCase();
            DataContext.getDocuments().success(function(largeLoad){
                //filter the data when searching
                data = $scope.customFilter(largeLoad).filter(function(item){
                    return JSON.stringify(item).toLowerCase().indexOf(ft) != -1;
                })
                $scope.setPagingData($scope.customFilter(data),page,pageSize);
            })
        }
        else{
            DataContext.getDocuments().success(function(largeLoad){
                var testLargeLoad = $scope.customFilter(largeLoad);
                //filter the data on initial page load when no search text has been entered
                $scope.setPagingData(testLargeLoad,page,pageSize);
            })
        }
    };
    //paging
    $scope.setPagingData = function(data, page, pageSize){
        var pagedData = data.slice((page -1) * pageSize, page * pageSize);
        //filter the data for paging
        $scope.myData = $scope.customFilter(pagedData);
        $scope.myData = pagedData;
        $scope.totalServerItems = data.length;
//        if(!$scope.$$phase){
//            $scope.$apply();
//        }
    }
    //watch for filter option change, set the data property of gridOptions to the newly filtered data
    $scope.$watch('selectedFilterOption',function(){
        var data = $scope.customFilter($scope.myData);
        $scope.myData = data;
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
        $scope.setPagingData($scope.myData,$scope.pagingOptions.currentPage,$scope.pagingOptions.pageSize);
    })
    $scope.$watch('pagingOptions',function(newVal, oldVal){
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize,$scope.pagingOptions.currentPage,$scope.filterOptions.filterText);
        $scope.setPagingData($scope.myData,$scope.pagingOptions.currentPage,$scope.pagingOptions.pageSize);
    },true)

    $scope.message ="This is a message";
    $scope.gridOptions = {
        data: 'myData',
        enablePaging: true,
        showFooter:true,
        totalServerItems: 'totalServerItems',
        pagingOptions: $scope.pagingOptions,
        filterOptions: $scope.filterOptions,
        enableCellEdit: true,
        enableColumnReordering: true,
        enablePinning: true,
        showGroupPanel: true,
        groupsCollapsedByDefault: true,
        enableColumnResize: true
    }
    $scope.gridOptions = GridOptionsService.getGridOptions('documents');
    //get the data on page load
    $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
}]);

我硬编码到控制器中的网格选项与服务返回的网格选项相同。我不明白的是为什么网格呈现,下拉过滤器工作,但分页被打破,只有当网格的选项来自一个服务?但如果它硬编码到控制器中,它就会像预期的那样工作。

编辑:如果有人能更雄辩地陈述我的问题,请随意编辑标题。

我真的不知道ngrid是如何实现的,但是我知道在许多指令中存在一个常见的陷阱,就是它们期望它们的配置在初始化后就准备好。这意味着,它们不会观察配置对象,而是假设它存在,并直接在link'controller函数中使用它,该函数在创建后立即运行。

如果确实是这种情况,一个快速的解决方法是只有当你有配置对象时才初始化指令。假设你通过作用域中的变量'options'传递配置对象,然后你会这样写:

<!-- If options exists on your scope, it means you fetched it from the server -->
<div ng-if="options">
    <div ng-grid ng-grid-options="options"></div>
</div>

再次,我不熟悉ngrid或它的用法,这只是一个有根据的猜测,采取结论并将其应用于正确的API。

我还没有对此进行测试,但一个可能的问题是您正在覆盖$作用域上的对象。这可以打破双向绑定。要进行快速测试,请键入

    $scope.grid = {
        Options: {
            data: 'myData',
            enablePaging: true,
            showFooter:true,
            totalServerItems: 'totalServerItems',
            pagingOptions: $scope.pagingOptions,
            filterOptions: $scope.filterOptions,
            enableCellEdit: true,
            enableColumnReordering: true,
            enablePinning: true,
            showGroupPanel: true,
            groupsCollapsedByDefault: true,
            enableColumnResize: true
        }
   }
   $scope.grid.Options = GridOptionsService.getGridOptions('documents');

你当然也需要更新指令属性中的网格选项

问题是用于过滤和分页的控制器函数使用控制器$scope上定义的选项,但是ng-grid UI没有绑定到这些对象。

过滤和分页的控制器方法使用$scope.pagingOptions作为数据源。但是,ng-grid UI绑定到$scope.gridOptions.pagingOptions。当您在控制器中显式地创建$scope.gridOptions时,$scope.gridOptions.pagingOptions引用与$scope.gridOptions相同的对象,因此在UI中进行更改将更改控制器函数中使用的值。

但是,当业务分配$scope.gridOptions时,业务正在创建新的pagingOptions,因此$scope.gridOptions.pagingOptions$scope.pagingOptions之间没有连接。修改UI不会改变控制器函数中使用的值。

对于filterOptions也是如此。

解决这个问题的一个方法是

$scope.gridOptions = GridOptionsService.getGridOptions('documents');
$scope.pagingOptions = $scope.gridOptions.pagingOptions
$scope.filterOptions = $scope.gridOptions.filterOptions