angular-ui / ui-grid

UI Grid: an Angular Data Grid
http://ui-grid.info
MIT License
5.39k stars 2.47k forks source link

Error on second display of modal, 'Error: [$compile:ctreq] Controller 'uiGrid', required by directive 'uiGridHeaderCell' #4421

Open aceb694 opened 9 years ago

aceb694 commented 9 years ago

I am getting the 'Error: [$compile:ctreq] Controller 'uiGrid', required by directive 'uiGridHeaderCell', can't be found!' error when trying to implement a custom filter modal. The same error is reproducable in the custom filter tutorial (http://ui-grid.info/docs/#/tutorial/306_custom_filters). Both errors appear only upon the second load of the modal and don't seem to cause any functionality problems but it would be great to have a way to get rid of them. To reproduce it in the Grid UI custom filter tutorial click on the '...' on the Age header then click filter to close it, then click on '...' again. On the second time the error below will appear.

Produced by my custom filter modal: image

Prouded by the custom filter modal in the Grid UI tutorial (). The error will display on the second time. image

hassandad commented 8 years ago

I am having same issue. Even the tutorial page generates same error. Please provide its solution.

ghiscoding commented 8 years ago

Have you found any ways to counter or hide this problem?

Also found this being a possible duplicate of issue 3655. This other issue 1791.

Seems like an old issue that wasn't fixed.

ghost commented 8 years ago

Hi there, issue is still alive. Can anyone help please?

shershen08 commented 8 years ago

+1

gcmestre commented 8 years ago

+1

JZehet commented 8 years ago

We solved this problem with the following lines:

//creates a isolated scope. When you want to have access to the parent scope set "isolate" to false _isoscope = $scope.$new(true);

//work with the scope as you want _isoscope.gridSelectionList = {}; _isoscope.gridSelectionList.showGridFooter = false; _isoscope................

//show this as modal angular.element(document.body).prepend(htmlModalTemplate); $compile(htmlElement)(_isoscope);

//when closing remove it from the DOM htmlModalTemplate.remove();

//remove the new scope _isoscope.$destroy();

ajitarya commented 7 years ago

Hi Guys,

I am new to angular, only know basics. I was wondering if anyone can please tell me how to fix this issue in the same example as it is available in the ui-grid example 306 `var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.selection']);

app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) { var today = new Date(); var nextWeek = new Date(); nextWeek.setDate(nextWeek.getDate() + 7);

$scope.gridOptions = {
    enableFiltering: true,
    onRegisterApi: function (gridApi) {
        $scope.gridApi = gridApi;
    },
    columnDefs: [
      { field: 'name' },
      {
          field: 'gender',
          filterHeaderTemplate: '<div class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><div my-custom-dropdown></div></div>',
          filter: {
              term: 1,
              options: [{ id: 1, value: 'male' }, { id: 2, value: 'female' }]     // custom attribute that goes with custom directive above 
          },
          cellFilter: 'mapGender'
      },
      { field: 'company', enableFiltering: false },
      { field: 'email', enableFiltering: false },
      { field: 'phone', enableFiltering: false },
      {
          field: 'age',
          filterHeaderTemplate: '<div class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><div my-custom-modal></div></div>'
      },
      { field: 'mixedDate', cellFilter: 'date', width: '15%', enableFiltering: false }
    ]
};

$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/500_complex.json')
  .success(function (data) {
      $scope.gridOptions.data = data;
      $scope.gridOptions.data[0].age = -5;

      data.forEach(function addDates(row, index) {
          row.mixedDate = new Date();
          row.mixedDate.setDate(today.getDate() + (index % 14));
          row.gender = row.gender === 'male' ? '1' : '2';
      });
  });

}])

.filter('mapGender', function () { var genderHash = { 1: 'male', 2: 'female' };

return function (input) {
    if (!input) {
        return '';
    } else {
        return genderHash[input];
    }
};

})

.directive('myCustomDropdown', function () { return { template: '' }; })

.controller('myCustomModalCtrl', function ($scope, $compile, $timeout) { var $elm;

$scope.showAgeModal = function () {
    $scope.listOfAges = [];

    $scope.col.grid.appScope.gridOptions.data.forEach(function (row) {
        if ($scope.listOfAges.indexOf(row.age) === -1) {
            $scope.listOfAges.push(row.age);
        }
    });
    $scope.listOfAges.sort();

    $scope.gridOptions = {
        data: [],
        enableColumnMenus: true,
        onRegisterApi: function (gridApi) {
            $scope.gridApi = gridApi;

            if ($scope.colFilter && $scope.colFilter.listTerm) {
                $timeout(function () {
                    $scope.colFilter.listTerm.forEach(function (age) {
                        var entities = $scope.gridOptions.data.filter(function (row) {
                            return row.age === age;
                        });

                        if (entities.length > 0) {
                            $scope.gridApi.selection.selectRow(entities[0]);
                        }
                    });
                });
            }
        }
    };

    $scope.listOfAges.forEach(function (age) {
        $scope.gridOptions.data.push({ age: age });
    });

    var html = '<div class="modal" ng-style="{display: \'block\'}"><div class="modal-dialog"><div class="modal-content"><div class="modal-header">Filter Ages</div><div class="modal-body"><div id="grid1" ui-grid="gridOptions" ui-grid-selection class="modalGrid"></div></div><div class="modal-footer"><button id="buttonClose" class="btn btn-primary" ng-click="close()">Filter</button></div></div></div></div>';
    $elm = angular.element(html);
    angular.element(document.body).prepend($elm);

    $compile($elm)($scope);

};

$scope.close = function () {
    var ages = $scope.gridApi.selection.getSelectedRows();
    $scope.colFilter.listTerm = [];

    ages.forEach(function (age) {
        $scope.colFilter.listTerm.push(age.age);
    });

    $scope.colFilter.term = $scope.colFilter.listTerm.join(', ');
    $scope.colFilter.condition = new RegExp($scope.colFilter.listTerm.join('|'));

    if ($elm) {
        $elm.remove();
    }
};

})

.directive('myCustomModal', function () { return { template: '', controller: 'myCustomModalCtrl' }; }) ;`

zamb3zi commented 7 years ago

I was also suffering this problem and I've just solved it partly from @JZehet's comment and partly from reading this article. Note however, the article claims it's important to $destroy before .remove().

In short, I have a directive which refreshes itself by removing the element children and re-building them, similar to the bnBadIf directive in the article. The difference is I am calling $compile(element)(scope) to compile the re-built elements rather than transclusion. As with the modal issue, everything is fine until the second time the directive re-builds. The solution was to create a child scope as follows:

...
link(scope, element, attrs) {
    let elementScope;
    scope.watch(..., function() {
        if(elementScope)
            elementScope.$destroy();
        element.children().remove();
        elementScope = scope.$new();
        ... re-build children including ui-grid etc, use elementScope for any $watches  ...
        $compile(element)(elementScope);
    });
}

Works like a charm!

zamb3zi commented 7 years ago

@ajitarya This should also solve your problem:

var elementScope;
$scope.showAgeModal = function () {
    if(elementScope) elementScope.$destroy();
    elementScope = $scope.$new();
    ...
    $compile($elm)(elementScope);
};
$scope.close = function () {
    ...
    if(elementScope) {
        elementScope.$destroy();
        elementScope = null;
    }
    if($elm) {
        $elm.remove();
        $elm = null;
    }
};
fcarvalhodev commented 7 years ago

This answer what @zamb3zi has posted, solved my problem here.

zios07 commented 6 years ago

@zamb3zi you saved my day ! thank you