UI-select в табличной строке

188
30 декабря 2018, 04:20

Имеется следующая DOM-структура: modalDiv (модальное окно) -> ui-grid -> ui-select. В модальном окне находится грид, в колонке которого располагается ui-select.

Проблема 1: в ui-grid стоит свой overflow для строки. В связи с этим, внутренние элементы обрезаются высотой строки таблицы. Т.е. если я раскрываю select, то options обрезаются высотой строки. Для решения этой проблемы я добавляю директиву append-to-body в ui-select, которая закрепляет элемент в body. Но в этой связи позникает следующая проблема.

Проблема 2: поскольку грид находится в модальном окне, а селект закрепляется в body, то при скролле модального окна, селект располагается относительно body и скролится вместе с модалкой (как будто бы он fixed).

Как можно решить эту проблему? Попробовал вместо ui-select вставить нативный <select>, то проблема решается интересным приемом: блокируется скролл до тех пора, пока select находится в раскрытом состоянии. Но нативный селект не устраивает, т.к. его стилизовать не удобно. Возможно, можно как-то решить проблему по-другому? Если нет, то как можно блокировать скролл (не убирать overflow: hidden, т.к. будет модалка "дрожать") пока селект раскрыт и вновь включать скролл, когда селект закрыт?

Воспроизвел проблему в редакторе. Попробуйте без модалки открыть селект и поскроллить страницу, а затем откройте модалку и повторите действия. Проблема станет очевидной.

angular.module('myApp', ['ui.grid', 'ui.select', 'ui.bootstrap']); 
 
angular 
  .module('myApp') 
  .controller('mainCtrl', ['$uibModal', function ($uibModal) { 
    const vm = this; 
     
    var myTemplate = '<ui-select-wrap>\n' + 
          '    <ui-select class="my-dropdown" ng-model="MODEL_COL_FIELD"\n' + 
          '               append-to-body="true">\n' + 
          '        <ui-select-match>{{ COL_FIELD }}</ui-select-match>\n' + 
          '        <ui-select-choices repeat="item in col.colDef.editDropdownOptionsArray | filter: $select.search">\n' + 
          '            <span>{{ item }}</span>\n' + 
          '        </ui-select-choices>\n' + 
          '    </ui-select>\n' + 
          '</ui-select-wrap>'; 
   
  vm.open = function () { 
    $uibModal.open({ 
      template: '<h3>А теперь попробуйте тут открыть Select и поскролить :(</h3>' + 
      '<div ui-grid="$ctrl.gridOptions"></div>', 
      controller: 'mainCtrl', 
      controllerAs: '$ctrl', 
      resolve: { 
        gridOptions: function () { 
          return vm.gridOptions; 
        } 
      } 
    }); 
  } 
   
  vm.gridOptions = { 
      columnDefs: [ 
        { name: 'status', width: '50%' }, 
        {  
          name: 'name', 
          cellTemplate: myTemplate, 
          editDropdownOptionsArray: ['John', 'Bob', 'Alice'] 
        } 
      ], 
      data: [ 
        { status: 'New' }, 
        { status: 'New' } 
      ], 
      rowHeight: 40 
    }; 
  }]);
.my-dropdown { 
  z-index: 1100 !important; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.2/angular.min.js"></script> 
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.6.3/ui-grid.css" rel="stylesheet"/> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.6.3/ui-grid.core.min.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.6.3/ui-grid.edit.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.20.0/select.js"></script> 
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.20.0/select.css" rel="stylesheet"/> 
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet"> 
 
<body ng-app="myApp"> 
  <div ng-controller="mainCtrl as main"> 
    <button ng-click="main.open()">ОТРЫТЬ МОДАЛКУ</button> 
    <h3>Здесь Select работает как нужно. Откройте селект и попробуйте проскролить окно: селект находится на месте. Теперь откройте модалку.</h3> 
    <div ui-grid="main.gridOptions"></div> 
  </div> 
</body>

Answer 1

Можно попробовать написать свою директиву.

Потом манипулировать с селектом так, как надо.

пример:

angular.module('myApp', ['ui.grid', 'ui.select', 'ui.bootstrap']); 
 
angular 
  .module('myApp') 
  .directive('uiSelectFix', function() { 
    return { 
      link: function(scope, element, attr) { 
        const cell = element.parent().parent(); 
        // устанавливаем ширину селекта 
        function setWidth(width) { 
          const uiWrap = element.parent(); 
          uiWrap.css({ 
            maxWidth: width, 
            minWidth: width 
          }); 
        }; 
        // выносим select из ячейки, что бы overflow на него не работал 
        function init() { 
          const uiWrap = element.parent(); 
          const row = uiWrap.parent().parent(); 
          uiWrap.css({ 
            position: 'absolute', 
            right: 0 
          }); 
          row.append(uiWrap); 
        }; 
        init(); 
        // Нужно для изменения размера, при ресайзе окна или родительского элемента 
        scope.$watch(function() { 
          return getComputedStyle(cell[0]).maxWidth; 
        }, function(n, o) { 
          if (n === 0) 
            return; 
          setWidth(n); 
        }) 
      } 
    }; 
  }) 
  .controller('mainCtrl', ['$uibModal', function($uibModal) { 
    const vm = this; 
 
    var myTemplate = '<ui-select-wrap>\n' + 
      '    <ui-select ui-select-fix class="my-dropdown" ng-model="MODEL_COL_FIELD"\n' + 
      '               >\n' + 
      '        <ui-select-match>{{ COL_FIELD }}</ui-select-match>\n' + 
      '        <ui-select-choices repeat="item in col.colDef.editDropdownOptionsArray | filter: $select.search">\n' + 
      '            <span>{{ item }}</span>\n' + 
      '        </ui-select-choices>\n' + 
      '    </ui-select>\n' + 
      '</ui-select-wrap>'; 
 
    vm.open = function() { 
      $uibModal.open({ 
        template: '<h3>А теперь попробуйте тут открыть Select и поскролить :(</h3>' + 
          '<div ui-grid="$ctrl.gridOptions"></div>', 
        controller: 'mainCtrl', 
        controllerAs: '$ctrl', 
        resolve: { 
          gridOptions: function() { 
            return vm.gridOptions; 
          } 
        } 
      }); 
    } 
 
    vm.gridOptions = { 
      columnDefs: [{ 
          name: 'status', 
          width: '50%' 
        }, 
        { 
          name: 'name', 
          cellTemplate: myTemplate, 
          editDropdownOptionsArray: ['John', 'Bob', 'Alice'] 
        } 
      ], 
      data: [{ 
          status: 'New' 
        }, 
        { 
          status: 'New' 
        } 
      ], 
      rowHeight: 40 
    }; 
  }]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.2/angular.min.js"></script> 
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.6.3/ui-grid.css" rel="stylesheet" /> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.6.3/ui-grid.core.min.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.6.3/ui-grid.edit.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.20.0/select.js"></script> 
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.20.0/select.css" rel="stylesheet" /> 
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet"> 
 
<body ng-app="myApp"> 
  <div ng-controller="mainCtrl as main"> 
    <button ng-click="main.open()">ОТРЫТЬ МОДАЛКУ</button> 
    <h3>Здесь Select работает как нужно. Откройте селект и попробуйте проскролить окно: селект находится на месте. Теперь откройте модалку.</h3> 
    <div ui-grid="main.gridOptions"></div> 
  </div> 
</body>

READ ALSO
Как выровнять форму по центру bootstrap 3?

Как выровнять форму по центру bootstrap 3?

Есть на картинка на которую нужно наложить форму и выровнять по центру

179
Проблема с выпадающим меню

Проблема с выпадающим меню

имеется проблема с выпадающим менюВ частности с КОНТАКТАМИ, оно почему-то ездит при сжимании страницы, а должно быть зафиксированным как...

254
Не могу вставить фоновое изображение на сайт, что делать?

Не могу вставить фоновое изображение на сайт, что делать?

Вставил картинку, обновляю страницу - фонового изображения нет, почему? Что я не так сделал?

162
Передача параметров HTML/JavaScript

Передача параметров HTML/JavaScript

Есть первая страница, на ней два поля ввод и кнопка "Войти", как по нажатию кнопки перейти на другую страницу, и передать в её JavaScript, строки...

178