ag-Grid - Is it possible to create a floating menu for each row? - html

I'm trying to create a menu that appears when a user hovers on a row, just like in the image below.
I did not find any built-in option to achieve this. Also tried using a custom CellRenderer function to create an element that I could move around later, but that didn't work as expected since it presented some other challenges (css wise) and was not really achieving the goal.
Is there a way to build this kind of menus in ag-Grid?

To work around the problem, you could use onCellMouseOver & onCellMouseOut methods:
var gridOptions = {
columnDefs: columnDefs,
onCellMouseOver : onCellMouseOver,
onCellMouseOut: onCellMouseOut,
...
};
Define both functions:
var onCellMouseOver = function(event){
//Get current row
var rowIndex = event.node.rowIndex;
var row = gridOptions.api.getDisplayedRowAtIndex(rowIndex);
//Set current row as not selected - in order to base on 'cellStyle' function
row.setSelected(true);
//Setup refresh params
var params = {
force: true, //Force refresh as cell value didn't change
rowNodes: [row]
};
//Refresh current row cells
gridOptions.api.refreshCells(params);
}
var onCellMouseOut = function(event){
//Get current row
var rowIndex = event.node.rowIndex;
var row = gridOptions.api.getDisplayedRowAtIndex(rowIndex);
//Set current row as not selected - in order to base on 'cellStyle' function
row.setSelected(false);
//Setup refresh params
var params = {
force: true, //Force refresh as cell value didn't change
rowNodes: [row]
};
Then define 'cellStyle' function for your column:
var columnDefs = [
{headerName: "your_column_name", field: "your_column",
cellStyle: function(params) {;
console.log('Is row selected', params.node.selected);
if (params.node.selected) {
return {display : 'none'};
} else {
return {display : 'inherit'};
}
}
}
];
You can find more about data refresh here: https://www.ag-grid.com/javascript-grid-refresh/
The full implementation of the code above might be found here: Working example
Second solution, edited after comments:
Another way is to use css classes to achieve the result.
{
headerName: "Price",
field: "price",
cellStyle: { "text-align": "center" },
cellRenderer: function(params) {
return (
"<div class='buttons'>" +
"<div class='back'>" +
params.value +
"</div>" +
"<div class='front'><button>Option A</button><button>Option B</button></div>" +
"</div>"
);
}
Buttons are shown on hover based on .ag-row-hover ag-grid class:
.front {
display: none;
}
.ag-row-hover .front {
display: inherit;
}
Working example

Related

Kendo Grid - accessing and manipulating the item object

Well I've gotten exactly zero responses to my half-dozen Angular-Kendo-UI grid questions, so I'm gonna cross my finger and hope my problems can be solved more generally. Maybe there's an easier way of manipulating the grid items.
I want to access the objects that contain my data (order items, in this case).
My grid's rows have a checkbox for selecting orders. When the user selects an order, I want to retrieve and manipulate that object.
// dataSource
vm.masterGrid.dataSource = new kendo.data.DataSource({
transport:{
read: function(options) {
return vm.getOrders(options);
}
},
pageSize: 5,
serverPaging: true,
});
//options
vm.masterGrid.gridOptions = {
columns: [
{ title: "Buyer", field: "BuyerName" },
{
title: "Select",
template: "<input " +
type='checkbox' " +
class='checkbox' " +
ng-disabled='#=!HasValidCustomsInfo#' " +
ng-click='ordersVm.selectForPackaging(Id)' " +
ng-model='Id'/>"
}
]
};
The view:
<div
kendo-grid
k-height="'400px'"
k-data-source="ordersVm.masterGrid.dataSource"
k-options="ordersVm.masterGrid.gridOptions">
</div>
Here's where I'm trying to get the object so I can do stuff with it:
// checkbox-click on row
vm.selectForPackaging = function (orderId) {
console.log(orderId); // returns true (useless)
console.log(vm.getOrderItemById(99)); // returns [init: {my actual object which I can't access}]
};
(My get-order-item-by-id helper function:)
vm.getOrderItemById = function (orderId) {
var matches = $filter('filter')( vm.masterGrid.dataSource.data(), function(gridItem, index) {
return gridItem.Id == orderId;
});
};
What I get back in vm.selectForPackaging actually contains my data but it isn't usable!
It looks like this in the console:
v init {_events: Object, _handlers: Object, OrderLines: init[1], Store: init, Id: 99…}
AddressIsValid:true
BuyerEmail:"lance.slack#gmail.com"
etc...
which would be fine, but I can't get it the data!
Calling vm.getOrderItemById(99).init should return my actual object. Instead it returns a function:
function (e){var t,n,i=this,r=function(){return i};we.fn.init.call(this),this._handlers={};for(n in e)t=e[n],"object"==typeof t&&t&&!t.getTime&&"_"!=n.charAt(0)&&(t=i.wrap(t,n,r)),i[n]=t;i.uid=_e.guid…
If I call that function: vm.getOrderItemById(99).init() I get undefined.
What am I doing wrong?
You can use the dataItem method to get the current row information
// checkbox-click on row
vm.selectForPackaging = function () {
var row = $(this).closest("tr"),
var grid = $(vm.masterGrid).data("kendoGrid"),
var dataItem = grid.dataItem(row);
console.log(dataItem);
};
Please refer the live example here

Is there a way to retrieve all editable cells from kendo grid?

I have a kendo grid in which fields are editable based on some condition like:
//var isEditable= some condition
fields: {
Id: { type: "int", editable: false },
Amount: {type: "number", editable: isEditable},
}
I want to get all editable cells and perforn something on them before they are displayed.
Currently i'm using dataBound event iterate rows and cells and find desired cells
dataBound: function(e){
var rows = e.sender.tbody.children();
for (var j = 0; j < rows.length; j++) {
var row = $(rows[j]);
if (isEditable){
var cell1 = row.children().eq("hardcoded index");
var cell2 = row.children().eq("hardcoded index 2");
var cell3 = row.children().eq("hardcoded index 3");
......
......
// perform action
}
}
Is there a better approach to achieve that?
Since you want to do something to the editable element before display, I would use a template to accomplish that. Here is an example that turns the background color red if the Amount field is editable:
<script id="editableTemplate" type="text/x-kendo-template">
#if (Editable) { #
<div style='background-color:red'>#=Amount#</div>
# } else { #
<div>#=Amount#</div>
# } #
<script>
Another way to approach this is to take parameters by wrapping the template in a function:
function foo(isEdit, value) {
if(isEdit){
return "<div style='background-color:red'>" + value + "</div>";
} else {
return "<div>" + value + "</div>";
}
}
You can then set the column template as:
{
field: "Amount",
type: "number",
template: function(data) {
return kendo.template("#=foo(isEditable, Amount)#")
},
editable: isEditable
}
Here is a basic fiddle.

How To Add Row at Bottom of Kendo Grid Dynamically

We use Kendo Grid for heads down data entry in an accounting application. We need the grid to behave similar to QuickBooks. Specifically, users should be able to:
Tab between cells
Automatically advance to the next row when tabbing off the last cell in a row.
Automatically add a new row when tabbing off the last cell of the last row.
However, we're having difficulty achieving this behavior. The last cell on the last row does not get saved before adding a new row to the bottom of the grid. If, however, we add a bogus column as the last column the proper behavior is achieved, but you have to tab through an extra, needless column which is unacceptable. The user needs to be able to enter and tab with new rows being added automatically. Here's the code:
function createGrid() {
var grid: any = $("#" + target).kendoGrid({
dataSource: gridDs,
edit: gridCellEdit,
editable: {
createAt: 'bottom'
},
filterable: true,
sortable: true,
navigatable: true,
resizable: true,
reorderable: true,
scrollable: { virtual: true },
columns: gridColumns,
dataBound: monitorKeyboard
});
}
function gridCellEdit(e) {
var input = e.container.find("input");
input.focus(function (e) {
input.select();
});
input.focus();
}
function monitorKeyboard(e) {
var grid = $('#' + e.sender.wrapper[0].id).data("kendoGrid");
$(grid.tbody).on("keydown", "td", function (e) {
// Monitor tabbing through columns
if (e.keyCode == 9) {
var row: any = $(this).closest("tr");
var rowIndex: number = $("tr", grid.tbody).index(row);
var colIndex: number = $("td", row).index(this);
var count: number = grid.dataSource.total();
var lastColIndex = row[0].cells.length - 1;
if (rowIndex == count - 1 && colIndex == lastColIndex) {
e.stopImmediatePropagation();
e.preventDefault();
grid.addRow();
grid.saveRow();
}
}
});
}

Titanium appcelerator : Lazy loading concept in table view while loading data using JSON

I have used Google Places API in order to display various places. I want at a time to display 20 places and when user scrolls the table view and reaches last field I want to add the rest of data and so on. I have created a function which returns the view and works perfectly excluding one thing. When further data is not available then it goes on loading the last data which is already loaded. Here goes my code.
Ti.include('Functions/get_lat_long.js');
var myTable = Ti.UI.createTableView();
var next_page;
var nxt_pge_tkn;
var tableData = [];
function json_parsing(url,firsttime,winloading)
{
var view1=Ti.UI.createView({
//height : '100%',
width : '100%',
backgroundColor : '#EDDA74',
top : '10%',
borderColor : "black"
});
//For storing url in case next_page_token variable is invalid
var curloc=Ti.App.Properties.getString("curlocation");
//calling method in order to retrive latitude and longitude of current location
get_latitude_longitude(curloc);
//setting the base url that have been initialized in global.js file
var baseurl=Ti.App.Properties.getString("preurl");
//storing lat and lng file that have been initialized in get_lat_lon.js file get_latitude_longitude function
var lat=Ti.App.Properties.getString("curlat");
var lng=Ti.App.Properties.getString("curlng");
//Storing radius which have been initialized in global.js file
var radiusmts=Ti.App.Properties.getInt("curradius")*1000;
//setting location type from the value that have been selected in app.js file by user
var loc_type=Ti.App.Properties.getString("curcategory");
//fetching and storing key which have been initialized in global.js file
var key=Ti.App.Properties.getString("apikey");
if(firsttime==true)
{
winloading.open();
var completeurl=baseurl+lat+","+lng+"&radius=" + radiusmts+ "&types=" + loc_type+ "&sensor=false&key=" + key;
}
else
{
winloading.show();
var completeurl=url;
}
var client = Ti.Network.createHTTPClient();
Ti.API.info("complete url " +completeurl);
client.open('GET',completeurl);
client.onload = function(e) {
//For getting next_page_token so that next page results could be displayed
var json = JSON.parse(this.responseText);
if(json.next_page_token)
{
Ti.API.info("Next page token found ");
next_page=true;
nxt_pge_tkn=json.next_page_token;
}
else
{
Ti.API.info("Next page token not found ");
next_page=false;
}
if(json.results.length==0)
{
var lblno_record=Titanium.UI.createLabel({
text : "No Record Found",
color : "black",
font : {fontSize : "25%" }
});
view1.add(lblno_record);
}
else
{
for(var i=0; i <json.results.length;i++)
{
//Ti.API.info("Place " + json.results[i].name+ " Lat " + json.results[i].geometry.location.lat + " Lng " + json.results[i].geometry.location.lng);
var row = Ti.UI.createTableViewRow({
className : "row"
//height : "80%"
});
//For temporary storing name in name variable
var name=json.results[i].name;
//Logic for shortening string in order to avoid overlapping of string
(name.length>35)?name=name.substr(0,34)+ "..." :name=name;
//Create label for displaying the name of place
var lblname=Ti.UI.createLabel({
//text : json.results[i].name,
text : name,
color : "black",
font : {fontSize : "20%"},
left : "22%",
top : "5%"
});
Ti.API.info("Name :- " + name);
row.add(lblname);
var add= json.results[i].vicinity;
(add.length>125) ? add=add.substr(0,123)+ ". ." : add=add;
var lbladdress=Ti.UI.createLabel({
text : add,
color : "black",
font : {fontSize : "15%"},
left : "22%",
top : "30%",
width : "71%"
});
row.add(lbladdress);
var imgico=Ti.UI.createImageView({
image : json.results[i].icon,
height : "90",
width : "90",
left : "1%",
top : "3%"
//bottom : "10%"
});
row.add(imgico);
tableData.push(row);
}
//setting data that have been set to mytable view
myTable.setData(tableData);
view1.add(myTable);
}
winloading.hide();
};
client.onerror=function(e){
alert("Network Not Avaliable");
};
myTable.addEventListener('scroll',function(e){
var first=e.firstVisibleItem;
var visible=e.visibleItemCount;
var total=e.totalItemCount;
Ti.API.info("Value of next_page_token before loop " + next_page);
if(next_page==true && first+visible==total )
{
Ti.API.info("Value of next_page_token in loop " + next_page);
var newurl="https://maps.googleapis.com/maps/api/place/nearbysearch/json?pagetoken="+nxt_pge_tkn+"&sensor=false&key="+key;
firsttime=false;
winloading.show();
//myTable.removeEventListener('scroll',function(e){});
json_parsing(newurl,firsttime,winloading);
//get_next_page(newurl);
}
});
client.send();
return view1;
client.clearCookies();
}
I was looking through your code and I would like to point:
There is an important issue with the block:
myTable.addEventListener('scroll',function(e){
...
});
this block is called each time you call your json_parsing function. Because of that you will have several functions attached to myTable scroll event. I'm sure that this isn't your intention. You should put it out of json_parsing.
About your specific issue you could try to look at the json.next_page_token value in your client.onload function:
client.onload = function(e) {
//For getting next_page_token so that next page results could be displayed
var json = JSON.parse(this.responseText);
Ti.API.info(JSON.stringify(this.responseText);
if(json.next_page_token)
{
...
maybe the value is an empty object {} or a 'false' string that will return a thruthy value. Don't forget that in javascript there are only 6 falsy values: false, undefined, null, 0, '' and NaN.
In practice this is a minor issue, but in documentation HTTPClient.onload and HTTPClient.onerror functions must be set before calling HTTPClient.open function
BTW, you have unreachable code at the end of your json_parsing function, but I think you already know that :-)
client.send();
return view1;
client.clearCookies(); //Unreachable code

Kendo UI Grid Get Row Values

I am trying to get the row item values (name, email, age) but I'm only able to get the first item by using the code below.
How can I get other row text by changing tr:eq(1) code or is there any other way to get two items value?
$("#grid_").kendoDropTarget({
drop: function (e) {
var data = grid.dataItem("tr:eq(1)");
// I only get first row but I need to dynamically get any row items.
alert(data.name);
}
});
plz try this..
var entityGrid = $("#DataGrid").data("kendoGrid");
var data = entityGrid.dataSource.data();
var totalNumber = data.length;
for(var i = 0; i<totalNumber; i++) {
var currentDataItem = data[i];
VersionIdArray[i] = currentDataItem.VersionId;
}
Thanks Sanjay however I was looking to just select a row items and this is what I got:
//Selecting Grid
var gview = $("#grid").data("kendoGrid");
//Getting selected item
var selectedItem = gview.dataItem(gview.select());
//accessing selected rows data
alert(selectedItem.email);
So it worked out perfect.
if your grid is set to selectable: true, use the following:
var mygrid = $("#grid").kendoGrid({
selectable: true
});
mygrid.on("click", "tr", function() {
var datarowindex = mygrid.data("kendoGrid").items().index(mygrid.data("kendoGrid").select());
var datarowid = mygrid.data("kendoGrid").dataItem(mygrid.data("kendoGrid").select()).MyId;
alert("index: " + datarowindex + " | value: " + datarowid);
});
if your Kendo UI Grid is set to selectable: false, use the following:
var mygrid = $("#grid").kendoGrid({
selectable: false
});
mygrid.on("click", "tr", function() {
var datarowindex = mygrid.data("kendoGrid").items().index($(this));
var datarowid = mygrid.data("kendoGrid").dataItem($(this).closest("tr")).MyId;
alert("index: " + datarowindex + " | value: " + datarowid);
});
where MyId is the property you are looking for.
I usually use the model from the event. Sometimes, actually very rarely, the row gets deselected and so, the .select() will return a 0 length object which will throw error while trying to access undefined properties.
You might be safer using: e.model.name