Is there a way to freeze the top-most row in a Vaadin Grid so that it can always be viewed, no matter how much the user scrolls vertically? I was looking at https://vaadin.com/docs/latest/components/grid/#column-freezing, but I'm not sure if this would help for rows.
Based on idea given in the commments, here is a proof of concept code that demonstrate how to do it Vaadin Grid.
Grid<String> grid = new Grid<>();
grid.setHeight("250px");
grid.setWidth("250px");
GridListDataView<String> dataView = grid.setItems("Zero","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten");
Column<String> col = grid.addColumn(value -> value.toString()).setHeader("A number");
HeaderRow row = grid.appendHeaderRow();
Div div = new Div();
div.setText(dataView.getItem(0).toString());
div.getElement().getStyle().set("text-align", "left");
div.getElement().getStyle().set("width", "100%");
row.getCell(col).setComponent(div);
grid.addSelectionListener(event -> {
event.getFirstSelectedItem().ifPresent(item -> {
div.setText(item.toString());
});
});
Related
I have a table in my UI which is a grid component. The value of one of the columns is calculated based on other column input values. So for example there are columns A,B, and C and value of column C = A + B. What I want to achieve is when user edits a row, before clicking the save button it would be able to see the calculated value in edit mode.
Is there a possibility to do that without Javascript or if not, how can I run a javascript snippet on onBlur event of the editable columns (A and B).
The calculated column is not editable by user.
This is a non functional code snippet that shows more or less what is the basis of my code.
Grid<Numbers> grid = new Grid<>(Numbers.class, false);
Editor<Numbers> editor = grid.getEditor();
Grid.Column<Numbers> aColumn = grid
.addColumn(Numbers::getA).setHeader("A")
.setWidth("120px").setFlexGrow(0);
Grid.Column<Numbers> bColumn = grid.addColumn(Numbers::getB)
.setHeader("B").setWidth("120px").setFlexGrow(0);
Grid.Column<Numbers> cColumn = grid.addColumn(Numbers::getC)
.setHeader("C");
Grid.Column<Numbers> editColumn = grid.addComponentColumn(numbers -> {
Button editButton = new Button("Edit");
editButton.addClickListener(e -> {
if (editor.isOpen())
editor.cancel();
grid.getEditor().editItem(numbers);
});
return editButton;
}).setWidth("150px").setFlexGrow(0);
Binder<Numbers> binder = new Binder<>(Numbers.class);
editor.setBinder(binder);
editor.setBuffered(true);
TextField aField = new TextField();
aField.setWidthFull();
binder.forField(aField)
.bind(Numbers::getA, Numbers::setA);
aColumn.setEditorComponent(aField);
TextField bField = new TextField();
bField.setWidthFull();
binder.forField(bField)
.bind(Numbers::getB, Numbers::setB);
bColumn.setEditorComponent(bField);
TextField cField = new TextField();
cField.setWidthFull();
binder.forField(cField)
.bind(Numbers::getC, Numbers::setC);
cColumn.setEditable(false);
Button saveButton = new Button("Save", e -> editor.save());
Button cancelButton = new Button(VaadinIcon.CLOSE.create(),
e -> editor.cancel());
cancelButton.addThemeVariants(ButtonVariant.LUMO_ICON,
ButtonVariant.LUMO_ERROR);
HorizontalLayout actions = new HorizontalLayout(saveButton,
cancelButton);
actions.setPadding(false);
editColumn.setEditorComponent(actions);
I tried adding this to some events:
Page.getCurrent().getJavaScript().execute("alert('the calculated value')");
The problem is the elements that are created by grid component have no id, so accessing them directly is not an option. Traversing dom is not really feasible too.
I have a kendo grid in my project,
#(Html.Kendo()
.Grid(Model)
.Name("BuilderGrid")
.Columns(columns =>
{
.......................
.......................
}).HtmlAttributes(new { style = "width:100%; height:100%;" })
grid data is loading fine. If I resize the browser window or resize the grid, last 2 or 3 grid rows are not showing, sometimes the last row showing cut .FYI -
I found it. need to add these lines, on page.
$(document).ready(function () {
$(window).resize(function () {
resizeGrid();
});
});
function resizeGrid() {
var gridWidget = $("#BuilderGrid").data("kendoGrid");
// apply the new height and trigger the layout readjustment
gridWidget.wrapper.height(847);
gridWidget.resize();
// force the layout readjustment without setting a new height
gridWidget.resize(true);
}
I'm using the angularjs ui-grid and I have a "total" row that I want to pin to the top of the grid no matter what is the current sorting.
How can I accomplish that?
I think this is what you are looking for : Row Pinning
Essentially add another hidden column, something like this:
{
field: 'pinned',
visible: false,
sort: {direction: uiGridConstants.ASC, priority: 0}, //use uiGridConstants.DESC for pinning to the bottom
suppressRemoveSort: true,
sortDirectionCycle: [uiGridConstants.ASC] //use uiGridConstants.DESC for pinning to the bottom
}
Row entities which have pinned = true rise to the top, even when other sorting are applied.
DISCLAIMER: I know it's not exactly answers the question, but this is how I solved it for now until I'll have a better solution:
Create an other grid above the main grid :
<div style="height:30px" ui-grid="totalGridOptions"></div>
<div ui-grid="gridOptions" class="grid"></div>
with definitions:
$scope.totalGridOptions = {showHeader:false,enableHorizontalScrollbar:false};
and then bind the columns of the main grid to the total grid (for width and other adjustments):
$scope.$watch('gridOptions', function (newVal) {
$scope.totalGridOptions.columnDefs = newVal.columnDefs;
}, true);
I think you should use something like this
$scope.gridOptions.data.unshift({label:value});
unshift adds it to the top
Edit 2 / Actual Solution: The way I finally settled this issue was by using custom header cell templates. I essentially create a second header row by adding a div at the bottom of what was previously my header. Here's a simple version:
<div class="super-special-header>
<div class="header-display-name">{{col.displayName}}</div>
<div class="totals-row">{{grid.appScope.totals[col.field]}}</div>
</div>
I store my totals on the controller's $scope and can access them in that div with grid.appScope.totals[whateverThisColumnIs]. This way I can still update them dynamically, but they don't get mixed into a sort function like my previous 'solution' was aiming for.
Edit 1 / Dead-end 'solution': Just ran into a problem with my solution, if your table is long (you have to scroll to get to bottom rows), the totals row will scroll out of view. Going to leave this 'solution' here so no one else makes the same mistake!
I had this same issue but with a twist. Since I was going to need to change the default sorting algorithms for many of the columns anyway, I set my algorithm up to skip the first element in the sort. You can use the sortingAlgorithm property on any columndef that would be part of a sortable column. This is really only a solution if you have only a few sortable columns though. It becomes unmaintainable for huge tables.
I couldn't find any built-in feature for ui-grid to keep a specific row at the top of the grid when sorting is applied. But this could be done using sortingAlgorithm parameter in the columnDefs( please refer to http://ui-grid.info/docs/#!/tutorial/Tutorial:%20102%20Sorting).
I have written an algorithm which keeps the row('total' is the particular cell value in the row) at the top of the grid without applying a sorting.
var sortingAlgorithm = function (a, b, rowA, rowB, direction) {
if (direction == 'total') {
if (a == 'total') {
return 0;
}
return (a < b) ? -1 : 1;
} else {
if (a == 'total') {
return 0;
}
if (b == 'total') {
return 1;
}
}
}
I have a splitter. In this splitter, I am implementing drag and drop functionality for the list view. Each list view is loaded in "table" format.
I want to drag my list view from left to right.
For the 1st list view, I have this code :
var listViewOptions = {
template: kendo.template(
$("#Firsttemplate").html()
),
dataSource: listdatSource,
};
var sourceListView = $("#First").kendoListView(listViewOptions).data("kendoListView");
var draggableOptions = {
filter: "table",
hint: function (e) {
return $('<div class="new">' + e.html() + '</div>');
}
}
sourceListView.element.kendoDraggable(draggableOptions);
In the filter, if I give "table" / "tbody" the whole content of list view is dragging in a row format and after dropping it is in the right side of splitter and is displaying in a single row. I want to display in the same format as in the leftside.
Can you tell me how to do this?
Thanks
somejQueryElement.html() gives you the inner HTML code of your element. Thus, if you filter on table elements, your argument e of the hint function is the table and e.html() is the content of the table.
If you want to have your table, you have to add reencapsulate the element in table tags :
var draggableOptions = {
filter: "table",
hint: function (e) {
return $('<div class="new"><table>' + e.html() + '</table></div>');
}
}
I created a multiselectable table in vaadin, but I can't select only a cell in this table when I click it selects all row.
Is there any way of selecting only a cell of a row ?
The title of the question doesn't reflect the actual question inside
Is there any way of selecting only a cell of a row ?
No. The whole point of a Vaadin table is to reflect rows of data in a tabular form. Setting a table to selectable keeps track of the itemIds of the selected rows with the table
You might be able to simulate selecting cells by using a ColumnGenerator in the table, and adding a listener to the generated component. Removing the listener may be tricky, however.
Alternatively, you may wish to simply generate components in a GridLayout and keep track of the selected cells yourself.
Ultimately, the approach here really depends upon exacly what you are trying to achieve.
It depends on what you're trying to accomplish. (Your question title and your question details are addressing two different questions.) If you're wondering whether or not you can target a specific cell and add a click listener to it, then yes, of course you can:
//initial layout setup
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
//Create a table and add a style to allow setting the row height in theme.
final Table table = new Table();
table.addStyleName("components-inside");
//Define the names and data types of columns.
//The "default value" parameter is meaningless here.
table.addContainerProperty("Sum", Label.class, null);
table.addContainerProperty("Is Transferred", CheckBox.class, null);
table.addContainerProperty("Comments", TextField.class, null);
table.addContainerProperty("Details", Button.class, null);
//Add a few items in the table.
for (int i=0; i<100; i++) {
// Create the fields for the current table row
Label sumField = new Label(String.format(
"Sum is <b>$%04.2f</b><br/><i>(VAT incl.)</i>",
new Object[] {new Double(Math.random()*1000)}),
Label.CONTENT_XHTML);
CheckBox transferredField = new CheckBox("is transferred");
//Multiline text field. This required modifying the
//height of the table row.
TextField commentsField = new TextField();
//commentsField.setRows(3);
//The Table item identifier for the row.
Integer itemId = new Integer(i);
//Create a button and handle its click. A Button does not
//know the item it is contained in, so we have to store the
//item ID as user-defined data.
Button detailsField = new Button("show details");
detailsField.setData(itemId);
detailsField.addListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
// Get the item identifier from the user-defined data.
Integer iid = (Integer)event.getButton().getData();
Notification.show("Link " +
iid.intValue() + " clicked.");
}
});
detailsField.addStyleName("link");
//Create the table row.
table.addItem(new Object[] {sumField, transferredField,
commentsField, detailsField},
itemId);
}
//Show just three rows because they are so high.
table.setPageLength(3);
layout.addComponent(table);
It might be beneficial to examine the documentation.