Меню ag-grid в липкой колонке

Есть ли способ добавить меню для каждой строки в липкой колонке (в Ag-grid)?

В официальном документе нет упоминания о такой функции, поэтому я не уверен, возможно ли это. Я пробовал несколько способов, но меню всегда заперто внутри липкой обертки столбца.

Единственный способ, с помощью которого я мог (по крайней мере) частично работать, - установить:

.ag-body-container .ag-row {
        z-index: 0;
    }

    .ag-ltr .ag-hacked-scroll .ag-pinned-right-cols-viewport {
        overflow: visible !important;
    }

но это полностью разрушило вертикальную прокрутку.

var columnDefs = [
    {headerName: "ID", width: 50,
        valueGetter: 'node.id',
        cellRenderer: 'loadingRenderer'
    },
    {headerName: "Athlete", field: "athlete", width: 150},
    {headerName: "Age", field: "age", width: 90},
    {headerName: "Country", field: "country", width: 120},
    {headerName: "Year", field: "year", width: 90},
    {headerName: "Date", field: "date", width: 110},
    {headerName: "Sport", field: "sport", width: 210},
    {headerName: "Gold", field: "gold", width: 300},
    {headerName: "Silver", field: "silver", width: 400},
    {headerName: "Bronze", field: "bronze", width: 200},
    {headerName: "Menu", field: "", width: 100, pinned: 'right', cellRenderer: 'menuRenderer' }
  ];
  
  function MenuRenderer( params ) {
  }	

	MenuRenderer.prototype.init = function(params) {
		this.eGui = document.createElement('div');
		this.eGui.classList.add('menu');
		var menuElement = '
			<a href="#">  * </a> 
			<div class="menu--list"> 
			</div>
		';
		this.eGui.innerHTML = menuElement;
	};

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


  var gridOptions = {
    components:{
        loadingRenderer: function(params) {
            if (params.value !== undefined) {
                return params.value;
            } else {
                return '<img src="./loading.gif">'
            }
        },
		'menuRenderer': MenuRenderer

    },
    columnDefs: columnDefs,
	rowBuffer: 0,
	rowModelType: 'infinite',
	paginationPageSize: 100,
	cacheOverflowSize: 2,
	maxConcurrentDatasourceRequests: 2,
	infiniteInitialRowCount: 0,
	maxBlocksInCache: 2,
	//embedFullWidthRows:true, 
    onGridReady: function (params) {
      params.api.sizeColumnsToFit();
    }
  }

  // wait for the document to be loaded, otherwise,
  // ag-Grid will not find the div in the document.

  document.addEventListener("DOMContentLoaded", function() {
    // lookup the container we want the Grid to use
    var eGridDiv = document.querySelector('#myGrid');

    // create the grid passing in the div to use together with the columns & data we want to use
    new agGrid.Grid(eGridDiv, gridOptions);
	
	 agGrid.simpleHttpRequest({url: 'https://raw.githubusercontent.com/ag-grid/ag-grid-docs/master/src/olympicWinners.json'}).then(function(data) {
        var dataSource = {
            rowCount: null, // behave as infinite scroll
            getRows: function (params) {
                console.log('asking for ' + params.startRow + ' to ' + params.endRow);
                // At this point in your code, you would call the server, using $http if in AngularJS 1.x.
                // To make the demo look real, wait for 500ms before returning
                setTimeout( function() {
                    // take a slice of the total rows
                    var rowsThisPage = data.slice(params.startRow, params.endRow);
                    // if on or after the last page, work out the last row.
                    var lastRow = -1;
                    if (data.length <= params.endRow) {
                        lastRow = data.length;
                    }
                    // call the success callback
                    params.successCallback(rowsThisPage, lastRow);
                }, 500);
            }
        };

        gridOptions.api.setDatasource(dataSource);
    });
  });
/* Menu */
	.menu {
		z-index: 2 !important;
		position: fixed;
		top: 20%;
		left: 50%;
	}
	
	.menu a {
		text-decoration: none;
	}
	
	.menu .menu--list {
		display: none;
		position: absolute;
		top: 0;
		right: 0px;
		width: 100px;
		height: 50px;
		border: 1px solid red;
	}
	
	.ag-body-container .ag-row {
		z-index: 0;
	}

	.ag-ltr .ag-hacked-scroll .ag-pinned-right-cols-viewport {
		overflow: visible !important;
	}
	
	.ag-pinned-right-cols-viewport .ag-row:first-child .menu--list{
		display: block;
	}

	/* [Layout] */
  .fill-height-or-more {
    min-height: 100%;
    display: flex;
    flex-direction: column;
    border: 1px solid red;
  }
  .fill-height-or-more > div {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }

  .some-area > div {
    padding: 1rem;
  }
  .some-area > div:nth-child(1) {
    flex-grow:0;
    background: #88cc66;
  }
  .some-area > div:nth-child(2) {
    flex-grow: 0;
    background: #ec971f;
  }
  .some-area > div:nth-child(3) {
    position: relative;
    padding: 0;
    justify-content: stretch;
    align-content: flex-start;;
    flex-grow:1;
    background: #8cbfd9;
  }
  .some-area > div:nth-child(4) {
    flex-grow: 0;
	position: absolute;
    background: #ec971f;
  }
  .some-area > div h2 {
    margin: 0 0 0.2rem 0;
  }
  .some-area > div p {
    margin: 0;
  }
  .inner{ position: absolute; top: 0; bottom: 0; left: 0; right: 0; }

  html, body {
    padding:0;
	margin: 0;
    height: 100%;
	overflow: hidden;
  }
  
  .ag-body-viewport {
	-webkit-overflow-scrolling: touch;
	}
<head>
  <script src="https://unpkg.com/ag-grid/dist/ag-grid.min.js"></script>
</head>

<html>
  <body>
  <section class="some-area fill-height-or-more">
    <div>
      Header
    </div>
    <div>
      Action bar
    </div>
    <div>
      <div class="inner">
        <div id="myGrid" style="height: 100%; width:100%; font-size: 1.4rem" class="ag-theme-fresh"></div>
      </div>
    </div>
  </section>
  </body> 	
</html>

Ответы

Ответ 1

Я бы полностью отказался от идеи добавления меню внутри ячейки.

Вместо этого я сделаю следующее:

  • Добавьте меню вне сетки, спрятано,
  • Держите ссылку в ячейке (это вызовет меню позже)
  • Добавить событие click к этой ссылке
  • Создайте класс для меню (может быть глобальным, поскольку будет только одно меню с изменяющимся контекстом)
    • Это скроет/покажет меню
    • Имейте параметры, которые хранят контекст (данные из вашей сетки или что-то еще)
  • Событие клика по ссылкам из сетки будет иметь код, который показывает меню

Что-то вроде этого: этот пример не имеет ошибок для краткости.

var gridMenu = function(selector) {
    var instance = this;
    instance.element = document.querySelector(selector);
    instance.context = null; // this can be any data, depends on your project

    // sender is the link from your cell
    // context is your data (see above)
    instance.open = function(sender, context) {
        instance.context = context;
        // you may even add the sender element to your context

        instance.element.style.display('block');
        // alternatively, you could use instance.element.classList.add('some_class_to_make_menu_visible')
        // you may need to add some positioning code here (sender would contain valuable data for that)
    }

    instance.close = function () {
        instance.context = null;
        instance.element.style.display = 'none';
        // or you may remove visibility class
    }

    // click events for menu items (if you use some Javascript processing, and the menu doesn't use simple links)
    instance.menuItem1Click = function(e) {
         // do whatever you wish here
         instance.close();
         // call this at the end of each of your menu item click event handlers
    }

    // ... more click event handlers for your other menu items (one for each menu item)

    return instance;
}

// Create your menu item somewhere in your document ready code, or even where you initiate your grid (before initializing the grid)
var menu = new gridMenu("#my_awesome_floating_menu");

Это пример события щелчка ваших ссылок внутри сетки:

function cellLinkClick(event) {
    var context = {}; // whatever data you may want to send to the menu
    menu.open(event, context);
}