Ограничение agRichSelectCellEditor n-элементами?

#ag-grid #ag-grid-angular

#ag-сетка #ag-grid-угловой

Вопрос:

Есть ли какой-либо способ ограничить высоту (например, до n * .cellHeight) для встроенного agRichSelectCellEditor?

Я вижу, что есть CellRenderer, но это влияет только на отдельные элементы списка — я знаю, что всегда могу реализовать пользовательский редактор, но хотел сначала посмотреть, возможно ли это

Комментарии:

1. можете ли вы подробнее рассказать об ограничении высоты (например, до n-количества элементов списка) ?

2. @sandeepjoshi итак, если высота отдельной ячейки (это настраивается) составляет 40 пикселей, то общая высота выпадающего списка должна составлять n * пикселей высоты ячейки

Ответ №1:

переопределить правило CSS .ag-rich-select-list

 .ag-rich-select-list {
  width: 100%;
  min-width: 200px;
  height: auto !important;
}
  

 var students = [{
  first_name: 'Bob',
  last_name: 'Harrison',
  gender: 'Male',
  address: '1197 Thunder Wagon Common, Cataract, RI, 02987-1016, US, (401) 747-0763',
  mood: "Happy",
  country: {
    name: 'Ireland',
    code: 'IE'
  }
}, {
  first_name: 'Mary',
  last_name: 'Wilson',
  gender: 'Female',
  age: 11,
  address: '3685 Rocky Glade, Showtucket, NU, X1E-9I0, CA, (867) 371-4215',
  mood: "Sad",
  country: {
    name: 'Ireland',
    code: 'IE'
  }
}, {
  first_name: 'Sadiq',
  last_name: 'Khan',
  gender: 'Male',
  age: 12,
  address: '3235 High Forest, Glen Campbell, MS, 39035-6845, US, (601) 638-8186',
  mood: "Happy",
  country: {
    name: 'Ireland',
    code: 'IE'
  }
}, {
  first_name: 'Jerry',
  last_name: 'Mane',
  gender: 'Male',
  age: 12,
  address: '2234 Sleepy Pony Mall , Drain, DC, 20078-4243, US, (202) 948-3634',
  mood: "Happy",
  country: {
    name: 'Ireland',
    code: 'IE'
  }
}];

// double the array twice, make more data!
students.forEach(function(item) {
  students.push(cloneObject(item));
});
students.forEach(function(item) {
  students.push(cloneObject(item));
});
students.forEach(function(item) {
  students.push(cloneObject(item));
});

function cloneObject(obj) {
  return JSON.parse(JSON.stringify(obj));
}

var columnDefs = [{
    field: "first_name",
    headerName: "First Name",
    width: 120,
    editable: true
  },
  {
    field: "last_name",
    headerName: "Last Name",
    width: 120,
    editable: true
  },
  {
    field: "gender",
    width: 100,
    editable: true,
    cellRenderer: 'genderCellRenderer',
    cellEditor: 'agRichSelectCellEditor',
    cellEditorParams: {
      cellRenderer: 'genderCellRenderer',
      values: ['Male', 'Female']
    }
  },
  {
    field: "age",
    width: 80,
    editable: true,
    cellEditor: 'numericCellEditor'
  },
  {
    field: "mood",
    width: 100,
    cellRenderer: 'moodCellRenderer',
    cellEditor: 'moodEditor',
    editable: true
  },
  {
    field: "country",
    width: 110,
    cellRenderer: 'countryCellRenderer',
    cellEditor: 'agRichSelectCellEditor',
    keyCreator: function(country) {
      return country.name;
    },
    cellEditorParams: {
      cellRenderer: 'countryCellRenderer',
      values: [{
          name: 'Ireland',
          code: 'IE'
        },
        {
          name: 'UK',
          code: 'UK'
        },
        {
          name: 'France',
          code: 'FR'
        }
      ]
    },
    editable: true
  },
  {
    field: "address",
    editable: true,
    cellEditor: 'agLargeTextCellEditor',
    cellEditorParams: {
      maxLength: '300', // override the editor defaults
      cols: '50',
      rows: '6'
    }
  }
];

var gridOptions = {
  columnDefs: columnDefs,
  rowData: students,
  defaultColDef: {
    editable: true,
    sortable: true,
    flex: 1,
    minWidth: 100,
    filter: true,
    resizable: true
  },
  onRowEditingStarted: function(event) {
    console.log('never called - not doing row editing');
  },
  onRowEditingStopped: function(event) {
    console.log('never called - not doing row editing');
  },
  onCellEditingStarted: function(event) {
    console.log('cellEditingStarted');
  },
  onCellEditingStopped: function(event) {
    console.log('cellEditingStopped');
  },
  components: {
    genderCellRenderer: GenderCellRenderer,
    numericCellEditor: NumericCellEditor,
    moodCellRenderer: MoodCellRenderer,
    moodEditor: MoodEditor,
    countryCellRenderer: CountryCellRenderer
  }
};

function getCharCodeFromEvent(event) {
  event = event || window.event;
  return (typeof event.which == "undefined") ? event.keyCode : event.which;
}

function isCharNumeric(charStr) {
  return !!/d/.test(charStr);
}

function isKeyPressedNumeric(event) {
  var charCode = getCharCodeFromEvent(event);
  var charStr = String.fromCharCode(charCode);
  return isCharNumeric(charStr);
}

// simple function cellRenderer, just returns back the name of the country
function CountryCellRenderer(params) {
  return params.value.name;
}

// function to act as a class
function NumericCellEditor() {}

// gets called once before the renderer is used
NumericCellEditor.prototype.init = function(params) {
  // create the cell
  this.eInput = document.createElement('input');

  if (isCharNumeric(params.charPress)) {
    this.eInput.value = params.charPress;
  } else {
    if (params.value !== undefined amp;amp; params.value !== null) {
      this.eInput.value = params.value;
    }
  }

  var that = this;
  this.eInput.addEventListener('keypress', function(event) {
    if (!isKeyPressedNumeric(event)) {
      that.eInput.focus();
      if (event.preventDefault) event.preventDefault();
    } else if (that.isKeyPressedNavigation(event)) {
      event.stopPropagation();
    }
  });

  // only start edit if key pressed is a number, not a letter
  var charPressIsNotANumber = params.charPress amp;amp; ('1234567890'.indexOf(params.charPress) < 0);
  this.cancelBeforeStart = charPressIsNotANumber;
};

NumericCellEditor.prototype.isKeyPressedNavigation = function(event) {
  return event.keyCode === 39 ||
    event.keyCode === 37;
};


// gets called once when grid ready to insert the element
NumericCellEditor.prototype.getGui = function() {
  return this.eInput;
};

// focus and select can be done after the gui is attached
NumericCellEditor.prototype.afterGuiAttached = function() {
  this.eInput.focus();
};

// returns the new value after editing
NumericCellEditor.prototype.isCancelBeforeStart = function() {
  return this.cancelBeforeStart;
};

// example - will reject the number if it contains the value 007
// - not very practical, but demonstrates the method.
NumericCellEditor.prototype.isCancelAfterEnd = function() {
  var value = this.getValue();
  return value.indexOf('007') >= 0;
};

// returns the new value after editing
NumericCellEditor.prototype.getValue = function() {
  return this.eInput.value;
};

// any cleanup we need to be done here
NumericCellEditor.prototype.destroy = function() {
  // but this example is simple, no cleanup, we could  even leave this method out as it's optional
};

// if true, then this editor will appear in a popup 
NumericCellEditor.prototype.isPopup = function() {
  // and we could leave this method out also, false is the default
  return false;
};


function GenderCellRenderer() {}

GenderCellRenderer.prototype.init = function(params) {
  this.eGui = document.createElement('span');
  if (params.value !== "" || params.value !== undefined || params.value !== null) {
    var gender = '<img border="0" width="15" height="10" src="https://raw.githubusercontent.com/ag-grid/ag-grid/master/grid-packages/ag-grid-docs/src/images/'   params.value.toLowerCase()   '.png">';
    this.eGui.innerHTML = gender   ' '   params.value;
  }
};

GenderCellRenderer.prototype.getGui = function() {
  return this.eGui;
};

function MoodCellRenderer() {}

MoodCellRenderer.prototype.init = function(params) {
  this.eGui = document.createElement('span');
  if (params.value !== "" || params.value !== undefined || params.value !== null) {
    var imgForMood = params.value === 'Happy' ? 'https://raw.githubusercontent.com/ag-grid/ag-grid/master/grid-packages/ag-grid-docs/src/images/smiley.png' : 'https://raw.githubusercontent.com/ag-grid/ag-grid/master/grid-packages/ag-grid-docs/src/images/smiley-sad.png';
    this.eGui.innerHTML = '<img width="20px" src="'   imgForMood   '" />';
  }
};

MoodCellRenderer.prototype.getGui = function() {
  return this.eGui;
};

function MoodEditor() {
  this.defaultImgStyle = 'padding-left:10px; padding-right:10px;  border: 1px solid transparent; padding: 4px;';
  this.selectedImgStyle = 'padding-left:10px; padding-right:10px; border: 1px solid lightgreen; padding: 4px;';
}

MoodEditor.prototype.onKeyDown = function(event) {
  var key = event.which || event.keyCode;
  if (key == 37 || // left
    key == 39) { // right
    this.toggleMood();
    event.stopPropagation();
  }
};

MoodEditor.prototype.toggleMood = function() {
  this.selectMood(this.mood === 'Happy' ? 'Sad' : 'Happy');
};

MoodEditor.prototype.init = function(params) {
  this.container = document.createElement('div');
  this.container.style = "border-radius: 15px; border: 1px solid grey;background: #e6e6e6;padding: 15px; text-align:center;display:inline-block;outline:none";
  this.container.tabIndex = "0"; // to allow the div to capture keypresses

  this.happyImg = document.createElement('img');
  this.happyImg.src = 'https://raw.githubusercontent.com/ag-grid/ag-grid/master/grid-packages/ag-grid-docs/src/images/smiley.png';
  this.happyImg.style = this.defaultImgStyle;

  this.sadImg = document.createElement('img');
  this.sadImg.src = 'https://raw.githubusercontent.com/ag-grid/ag-grid/master/grid-packages/ag-grid-docs/src/images/smiley-sad.png';
  this.sadImg.style = this.defaultImgStyle;

  this.container.appendChild(this.happyImg);
  this.container.appendChild(this.sadImg);

  var that = this;
  this.happyImg.addEventListener('click', function(event) {
    that.selectMood('Happy');
    params.stopEditing();
  });
  this.sadImg.addEventListener('click', function(event) {
    that.selectMood('Sad');
    params.stopEditing();
  });
  this.container.addEventListener('keydown', function(event) {
    that.onKeyDown(event)
  });

  this.selectMood(params.value);
};

MoodEditor.prototype.selectMood = function(mood) {
  this.mood = mood;
  this.happyImg.style = (mood === 'Happy') ? this.selectedImgStyle : this.defaultImgStyle;
  this.sadImg.style = (mood === 'Sad') ? this.selectedImgStyle : this.defaultImgStyle;
};

// gets called once when grid ready to insert the element
MoodEditor.prototype.getGui = function() {
  return this.container;
};

MoodEditor.prototype.afterGuiAttached = function() {
  this.container.focus();
};

MoodEditor.prototype.getValue = function() {
  return this.mood;
};

// any cleanup we need to be done here
MoodEditor.prototype.destroy = function() {};

MoodEditor.prototype.isPopup = function() {
  return true;
};

// setup the grid after the page has finished loading
document.addEventListener('DOMContentLoaded', function() {
  var gridDiv = document.querySelector('#myGrid');
  new agGrid.Grid(gridDiv, gridOptions);
});  
 .ag-rich-select-list {
  width: 100%;
  min-width: 200px;
  height: auto !important;
}  
 <!DOCTYPE html>
<html lang="en">

<head>
  <script>
    var __basePath = './';
  </script>
  <style media="only screen">
    html,
    body {
      height: 100%;
      width: 100%;
      margin: 0;
      box-sizing: border-box;
      -webkit-overflow-scrolling: touch;
    }
    
    html {
      position: absolute;
      top: 0;
      left: 0;
      padding: 0;
      overflow: auto;
    }
    
    body {
      padding: 1rem;
      overflow: auto;
    }
  </style>
  <script src="https://unpkg.com/@ag-grid-enterprise/all-modules@24.1.0/dist/ag-grid-enterprise.min.js"></script>
</head>

<body>
  <div id="myGrid" style="height: 100%;" class="ag-theme-alpine"></div>


</body>

</html>  

Комментарии:

1. Выглядит хорошо, но есть одна проблема: в моем приложении, если я заполняю всю сетку строками и запускаю редактирование из последней строки, выпадающий список переместит пробел вниз из нижней части сетки и последней строки, похоже, это вызвано height: auto

2. Похоже, что ag-grid динамически добавляет встроенный стиль для вычисления верхней / нижней части сетки при открытии выпадающего списка (например362px; top: 556px;»>) .. установка высоты: auto, похоже, нарушает эту логику внедрения

3. Похоже, это известная проблема с AG-Grid, которая будет решена AG-3332 в ag-grid.com/ag-grid-pipeline