
# Personalization settings

Personalization settings are a function that automatically or manually customizes the interface according to the user's preferences and usage patterns.

The functions used for personalization include layout, column hiding, fixing, filtering, and sorting.

Users can adjust them directly from the settings menu or easily personalize them through automatic recommendations during initial setup.

The personalization settings demo is an example that uses variables to help with understanding.

Since personalization information is not managed in the grid, you must directly prepare the logic or storage method for information management.

When processing the visible property when using a column group, use the visible of layout.

**If you change the settings such as column fixation, filter, and height using the grid's context menu and click the Add Personalization button, the layout will be added.**


```js
const fields = [
  { fieldName: 'KorName', dataType: 'text' },
  { fieldName: 'Gender', dataType: 'text' },
  { fieldName: 'Age', dataType: 'number' },
  { fieldName: 'Phone', dataType: 'text' },
  { fieldName: 'ProductId', dataType: 'text' },
  { fieldName: 'KorCountry', dataType: 'text' },
  { fieldName: 'OrderDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'CardNumber', dataType: 'text' },
  { fieldName: 'Monetary', dataType: 'text' },
  { fieldName: 'StartDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'EndDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'ToMonth', dataType: 'number' },
  { fieldName: 'Month', dataType: 'number' },
  { fieldName: 'Year', dataType: 'number' },
  { fieldName: 'InterestRate', dataType: 'number' },
  { fieldName: 'SaveCost', dataType: 'number' },
  { fieldName: 'SaveMaturity', dataType: 'number' },
  { fieldName: 'CurrentSave', dataType: 'number' }
];

const columns = [
  { name: 'KorCountry', fieldName: 'KorCountry', width: '100', header: { text: 'Investment Country' } },
  { name: 'Monetary', fieldName: 'Monetary', width: '70', header: { text: 'Currency' } },
  { name: 'KorName', fieldName: 'KorName', width: '70', header: { text: 'Name' } },
  { name: 'Gender', fieldName: 'Gender', width: '70', header: { text: 'Gender' } },
  { name: 'Age', fieldName: 'Age', width: '70', header: { text: 'Age' }, styleName: 'right-column' },
  { name: 'StartDate', fieldName: 'StartDate', width: '100', header: { text: 'First Payment Date' } },
  { name: 'EndDate', fieldName: 'EndDate', width: '100', header: { text: 'End Date' } },
  { name: 'ToMonth', fieldName: 'ToMonth', width: '70', header: { text: 'Payment Count' }, styleName: 'right-column' },
  { name: 'Month', fieldName: 'Month', width: '70', header: { text: 'Remaining Count' }, styleName: 'right-column' },
  { name: 'InterestRate', fieldName: 'InterestRate', width: '70', numberFormat: '0.00', header: { text: 'Interest Rate' }, groupFooter: { text: 'Subtotal: ' }, footer: { text: 'Total: ' }, styleName: 'right-column' },
  { name: 'SaveCost', fieldName: 'SaveCost', width: '80', numberFormat: '#,##0', header: { text: 'Payment Amount' }, groupFooter: { numberFormat: '#,##0', expression: 'sum' }, footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' },
  { name: 'SaveMaturity', fieldName: 'SaveMaturity', width: '80', numberFormat: '#,##0', header: { text: 'Maturity Amount' }, groupFooter: { numberFormat: '#,##0', expression: 'sum' }, footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' },
  { name: 'CurrentSave', fieldName: 'CurrentSave', width: '80', numberFormat: '#,##0', header: { text: 'Current Balance' }, groupFooter: { numberFormat: '#,##0', expression: 'sum' }, footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' }
];

let userCount = 1;
let personalizedList = {};

const { gridView, dataProvider } = RealGrid.createGrid('realgrid', {
  columns,
  header: {
    height: 40
  },
  display: {
    rowHeight: 36,
    emptyMessage: 'No data to display.'
  },
  edit: {
    insertable: true,
    appendable: true
  },
  footer: {
    height: 40
  },
  stateBar: {
    width: 16
  },
  groupPanel: {
    visible: true
  },
  onContextMenuPopup: function (grid, x, y, elementName) {
    if (elementName.cellType === 'header') {
      grid.setCurrent({ column: grid.mouseToIndex(x, y).column });
    }
    setContextMenu(gridView);
  },
  onContextMenuItemClicked: function (grid, item, clickData) {
    onContextMenuClick(grid, item, clickData);
  },
  onInitialized: (grid) => {
    fetch('/data/en/simple_data2700.json')
      .then((response) => response.json())
      .then((data) => {
        grid.getDataSource().setRows(data);
        personalizedList['default'] = {
          layout: null,
          rowGroup: [],
          sort: [],
          colFixed: 0,
          rowFixed: 0,
          rowHeight: 36
        };
      });
  }
}, {
  fields
});

window.gridView = gridView;
window.dataProvider = dataProvider;

function setContextMenu(grid) {
  const columns = grid.getColumnNames();
  const row = grid.getCurrent().itemIndex + 1;
  const visibleContextMenu = [];

  for (let i in columns) {
    const menuItem = {};
    const column = grid.layoutByName(columns[i]);
    if (column.column) {
      menuItem.label = column.lastColumn.header.text;
      menuItem.tag = column.lastColumn.name;
      menuItem.type = 'check';
      menuItem.checked = column.visible;
      visibleContextMenu.push(menuItem);
    }
  }

  visibleContextMenu.push(
    { label: '-' },
    { label: 'Show All Columns', tag: 'columnShow' },
    { label: '-' },
    { label: 'Turn on current column filter', tag: 'autoFilter' },
    { label: 'Turn off current column filter', tag: 'autoFilterFalse' }
  );

  const column = grid.columnByName(grid.getCurrent().column);
  const contextMenu = [
    {
      label: 'Fix',
      children: [
        { label: '1 Row', tag: '1rowFixed' },
        { label: '2 Rows', tag: '2rowFixed' },
        { label: 'Up to Current Row (' + row + ')', tag: 'rowFixed' },
        { label: '-' },
        { label: 'First Column', tag: '1colFixed' },
        { label: 'Second Column', tag: '2colFixed' },
        { label: 'Up to Current Column (' + column.header.text + ')', tag: 'colFixed' },
        { label: '-' },
        {
          label: 'Unfix',
          tag: 'cancelFixed',
          enabled: grid.fixedOptions.rightCount + grid.fixedOptions.colCount + grid.fixedOptions.rowCount !== 0
        }
      ]
    },
    { label: 'Column', tag: 'columnMenu', children: visibleContextMenu },
    {
      label: 'Row Height',
      children: [
        { label: 'Normal (28px)', tag: 'rowNormalHeight' },
        { label: 'Narrow (20px)', tag: 'rowSmallHeight' },
        { label: 'Wide (36px)', tag: 'rowLargeHeight' }
      ]
    }
  ];
  grid.setContextMenu(contextMenu);
}

function onContextMenuClick(grid, data, index) {
  const cell = grid.getCurrent();
  const col = grid.columnByName(cell.column);

  if (data.parent.label === 'Column' && data.tag !== 'columnShow' && data.tag !== 'autoFilter' && data.tag !== 'autoFilterFalse') {
    grid.layoutByName(data.tag).visible = data.checked;
  }

  switch (data.tag) {
    case '1rowFixed':
      grid.setFixedOptions({ rowCount: 1 });
      break;
    case '2rowFixed':
      grid.setFixedOptions({ rowCount: 2 });
      break;
    case 'rowFixed':
      grid.setFixedOptions({ rowCount: cell.itemIndex + 1 });
      break;
    case '1colFixed':
      grid.setFixedOptions({ colCount: 1 });
      break;
    case '2colFixed':
      grid.setFixedOptions({ colCount: 2 });
      break;
    case 'colFixed':
      grid.setFixedOptions({ colCount: col.displayIndex + 1 });
      break;
    case 'cancelFixed':
      grid.setFixedOptions({ colCount: 0, rowCount: 0 });
      break;
    case 'rowNormalHeight':
      grid.displayOptions.rowHeight = 28;
      break;
    case 'rowSmallHeight':
      grid.displayOptions.rowHeight = 20;
      break;
    case 'rowLargeHeight':
      grid.displayOptions.rowHeight = 36;
      break;
    case 'autoFilter':
      col.autoFilter = true;
      grid.refresh();
      break;
    case 'autoFilterFalse':
      col.autoFilter = false;
      grid.refresh();
      break;
    case 'columnHide':
      col.visible = false;
      break;
    case 'columnShow':
      {
        const layout = grid.getColumnNames();
        for (let i in layout) {
          gridView.layoutByName(layout[i]).visible = true;
        }
      }
      break;
  }
}

window.addPersonalizedList = function () {
  const select = document.getElementById('personalizedList');

  const option = document.createElement('option');
  option.value = 'user' + userCount;
  option.text = 'User' + userCount;

  select.appendChild(option);
  userCount++;

  const filterColumns = [];
  for (let i = 0; i < gridView.getColumns().length; i++) {
    if (gridView.columnByName(gridView.getColumns()[i].name).autoFilter) {
      filterColumns.push(gridView.getColumns()[i].name);
    }
  }

  const activeColumnFilters = [];
  for (let j = 0; j < filterColumns.length; j++) {
    const filterList = gridView.getActiveColumnFilters(filterColumns[j]);
    activeColumnFilters.push(filterList);
  }

  const selectedValue = option.value;
  personalizedList[selectedValue] = {
    layout: gridView.saveColumnLayout(),
    rowGroup: gridView.getGroupFieldNames(),
    sort: gridView.getSortedFields(),
    colFixed: gridView.fixedOptions.colCount,
    rowFixed: gridView.fixedOptions.rowCount,
    rowHeight: gridView.displayOptions.rowHeight,
    filterColumns: filterColumns,
    activeColumnFilters: activeColumnFilters
  };

  select.value = option.value;
};

window.removePersonalizedList = function () {
  const select = document.getElementById('personalizedList');
  if (select.value !== 'default') {
    select.remove(select.selectedIndex);
    defaultLayout();
  }
};

function defaultLayout() {
  gridView.setColumnLayout(null);
  gridView.fixedOptions.colCount = 0;
  gridView.fixedOptions.rowCount = 0;
  gridView.groupBy([]);
  gridView.displayOptions.rowHeight = 36;

  for (let i = 0; i < gridView.getColumns().length; i++) {
    gridView.columnByName(gridView.getColumns()[i].name).autoFilter = false;
  }

  gridView.orderBy([], []);
}

window.selectChange = function () {
  const layout = personalizedList[document.getElementById('personalizedList').value];

  gridView.setColumnLayout(layout.layout);
  gridView.fixedOptions.colCount = layout.colFixed;
  gridView.fixedOptions.rowCount = layout.rowFixed;
  gridView.groupBy(layout.rowGroup);
  gridView.displayOptions.rowHeight = layout.rowHeight;

  for (let i = 0; i < gridView.getColumns().length; i++) {
    gridView.columnByName(gridView.getColumns()[i].name).autoFilter = false;
  }
  if (layout.filterColumns) {
    for (let i = 0; i < layout.filterColumns.length; i++) {
      gridView.columnByName(layout.filterColumns[i]).autoFilter = true;
    }
  }

  const sortFields = [];
  const sortDirs = [];
  if (layout.sort) {
    for (let j = 0; j < layout.sort.length; j++) {
      sortFields.push(layout.sort[j].orgFieldName);
      sortDirs.push(layout.sort[j].direction);
    }
    gridView.orderBy(sortFields, sortDirs);
  } else {
    gridView.orderBy([], []);
  }
};

window.setColumnLayout = function () {
  const layout = [
    {
      name: 'Group1',
      direction: 'horizontal',
      items: ['KorCountry', 'Monetary'],
      header: { text: 'Country' }
    },
    {
      name: 'Group2',
      direction: 'horizontal',
      items: ['KorName', 'Gender', 'Age'],
      header: { text: 'User' }
    },
    {
      name: 'Group3',
      direction: 'horizontal',
      items: ['StartDate', 'EndDate'],
      header: { text: 'Date' }
    }
  ];

  gridView.setColumnLayout(layout);
};

window.setDefaultLayout = function () {
  gridView.setColumnLayout(null);
};
```

```js
var personalizedList = {};

//개인화 추가
function addPersonalizedList() {
  const select = document.getElementById('personalizedList');

  const option = document.createElement('option');
  option.value = 'user' + userCount;
  option.text = '사용자' + userCount;

  select.appendChild(option);
  userCount++;

  //컬럼 필터 정보 
  var filterColumns = [];
  for(var i = 0; i < gridView.getColumns().length; i++){
      if(gridView.columnByName(gridView.getColumns()[i].name).autoFilter){
          filterColumns.push(gridView.getColumns()[i].name)
      }
  }
  //각 컬럼 필터 목록
  var activeColumnFilters = []
  for(var j = 0; j < filterColumns.length; j++){
      var filterList = gridView.getActiveColumnFilters(filterColumns[j]);
      activeColumnFilters.push(filterList)
  }

  const selectedValue = option.value;
  personalizedList[selectedValue] = {
    columns: gridView.getColumns(),
    layout: gridView.saveColumnLayout(),
    rowGroup: gridView.getGroupFieldNames(),
    sort: gridView.getSortedFields(),
    colFixed: gridView.fixedOptions.colCount,
    rowFixed: gridView.fixedOptions.rowCount,
    rowHeight: gridView.displayOptions.rowHeight,
    filterColumns: filterColumns,
    activeColumnFilters: activeColumnFilters
  };

  select.value = option.value
}

//개인화 변경시
function selectChange(){
  var layout = personalizedList[document.getElementById('personalizedList').value];

  //레이아웃
  gridView.setColumnLayout(layout.layout);

  //고정
  gridView.fixedOptions.colCount = layout.colFixed;
  gridView.fixedOptions.rowCount = layout.rowFixed;

  //행 그룹핑
  gridView.groupBy(layout.rowGroup);
  //행 높이
  gridView.displayOptions.rowHeight = layout.rowHeight;

  //필터
  for(var i = 0; i < gridView.getColumns().length; i++){
    gridView.columnByName(gridView.getColumns()[i].name).autoFilter = false;
  }
  if(layout.filterColumns){
    for(var i = 0; i < layout.filterColumns.length; i++){
      gridView.columnByName(layout.filterColumns[i]).autoFilter = true;
    }
  }

  //정렬
  var sortFields = []
  var sortDirs = []
  if(layout.sort){
    for(var j = 0; j < layout.sort.length; j++){
      sortFields.push(layout.sort[j].orgFieldName);
      sortDirs.push(layout.sort[j].direction);
    }
    gridView.orderBy(sortFields, sortDirs);
  }else{
    gridView.orderBy([], []);
  } 
}
```