In the Grid widget in Vaadin 7.5.3, we can determine the current selection of rows by calling SelectionEvent::getSelected or Grid::getSelectedRows.
So how do we set the selection programmatically?
While that's true that official documentation for Grid class doesn't have this method stated, still you can do it programmatically. I won't argue whether it's a bug or not. Firstly you need to know what is your SelectionMode. Then you can select a row (or rows):
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
Customer c = new Customer(1);
container = new BeanItemContainer<>(Customer.class, Arrays.asList(c, new Customer(2)));
grid = new Grid(container);
grid.setSelectionMode(SelectionMode.SINGLE);
SingleSelectionModel m = (SingleSelectionModel) grid.getSelectionModel();
m.select(c);
layout.addComponents(grid);
setContent(layout);
}
In newer Vaadin (in my case 7.5.6) there is select(Object) method directly in Grid interface.
Example:
Grid grid = new Grid(container);
grid.setSelectionMode(Grid.SelectionMode.SINGLE);
grid.select(row);
The row object for example could be taken from SelectionListener event or from added before object (as in #kukis answer).
Setter Method Missing (bug?)
The Book of Vaadin mentions the setter method Grid::setSelectedRows along with a getter.
The currently selected rows can be set with setSelectedRows() by a collection of item IDs, and read with getSelectedRows().
However, the Grid class doc does not list that method. Nor does NetBeans 8.0.2 suggest that method in its auto-complete.
So apparently a bug. See Ticket # 18,580.
Related
I am doing some integration tests, and I have replaced some tables with a grid. At this moment, I have some visible columns by default and other columns are hidden as follows:
column6.setHidable(true);
column6.setHidden(true);
Now I am trying to do some integration tests. For getting the grid, I can use the method (is the only grid present in this view):
$(GridElement.class).first();
This works fine. But for my test (with Vaadin Testbench), I need to check some values that are inside the hidden columns of the grid. I am talking about this button:
I have tried to use the Vaadin debug console to get the name of the button that allows the user to show/hide columns, but the debug console only can select the entire grid element, not this menu.
Also I have check if inside the GridElement exists any kind of already implemented method that give me access to this menu without any success.
Usually, chrome developer tools (or similar for firefox and ie / edge, etc) is your best friend in such cases. So far I'm not aware of anything dedicated for that particular button. However you can workaround this limitation by selecting the items which compose this feature by their specific classes:
The below test method shows a quick implementation which should give you a starting point:
public class GridManipulationTest extends TestBenchTestCase {
#Before
public void setUp() throws Exception {
System.setProperty("webdriver.chrome.driver", "D:\\Kit\\chromedriver_win32\\chromedriver.exe");
setDriver(new ChromeDriver());
}
#After
public void tearDown() throws Exception {
// TODO uncomment below after checking all works as expected
//getDriver().quit();
}
#Test
public void shouldOpenGridColumnVisibilityPopupAndSelectItems() {
// class for the grid sidebar button
String sideBarButtonClass = "v-grid-sidebar-button";
// class for the sidebar content which gets created when the button is clicked
String sideBarContentClass = "v-grid-sidebar-content";
// xpath to select the item corresponding to the necessary column
// there are perhaps more "elegant" solutions, but this is what I came up with at the time
String columnMenuItemXpath = "//*[contains(#class, 'column-hiding-toggle')]/span/div[text()='Name']";
// open the browser
getDriver().get("http://localhost:8080/");
// get the first available grid
GridElement firstGrid = $(GridElement.class).first();
// look for the grid's sidebar button and click it
firstGrid.findElement((By.className(sideBarButtonClass))).click();
// the sidebar content is created outside the grid structure so don't look for it using the grid search context
WebElement sidebarContent = findElement(By.className(sideBarContentClass));
// look for the expected column name and click it
sidebarContent.findElement(By.xpath(columnMenuItemXpath)).click();
}
}
And of course what it looks like in action
I have 2 CustomTables with same column names. They are created using expandratio width.
I added resizecolumnlisteners to them so when user column in table1 resize also table2 and vice versa. Problem is when resizing with
List<Values> list;// list of objects in table;
table1.addresizeColumnListener(new resizeColumnListener(){
private void resizeColumn(Event)
{
for(int i=0; i<list.size(); i++)
{
table2.setColumnWidth(list.get(i), table1.getColumnWidth(list.get(i)));
}
}
in table changes only column where listener is fired all others dont change, only when i click any column again all column's widths in table2 is set from table1.
I have too low stackoverflow reputation level to add a comment - so I'm writing this answer.
First of all: Which version of Vaadin do you use? I can't find the function which you used:
table1.addresizeColumnListener(...)
In Vaadin latest documentation is addColumnResizeListener.
And I have doubt why you want change size of all column after notification that one column has been changed? I imagine that after each column size change the Table.ColumnResizeEvent should be emit.
I think the problem you are facing is that when you re-size something in the browser, it will not get sent to the server straight away. The update to the server is sent to the server along with the next update request. That is why you get the delayed update to the UI (if I understood it correctly).
To fix this you can try the code below. Notice the setImmediate(true). This will basically tells Vaadin that you want any update to the table to be sent to the server immediately when the user modifies the table properties.
Try this:
table1.setImmediate(true);
table1.addColumnResizeListener(new ColumnResizeListener(){
#Override
public void columnResize(ColumnResizeEvent event) {
table2.setColumnWidth(event.getPropertyId(), event.getCurrentWidth());
}
});
table2.setImmediate(true);
table2.addColumnResizeListener(new ColumnResizeListener(){
#Override
public void columnResize(ColumnResizeEvent event) {
table1.setColumnWidth(event.getPropertyId(), event.getCurrentWidth());
}
});
I have a simple use case: in a multi select Table
when the user selects 1 row, a context menu with two actions must be returned (DELETE and DOWNLOAD)
when the user selects more than one row, only the DELETE Action should be in the context menu
This is the code I use:
contactList.setMultiSelect(true);
final Action delete = new Action("Delete", FontAwesome.TIMES);
final Action download = new Action("Download", FontAwesome.DOWNLOAD);
contactList.addActionHandler(new Action.Handler() {
#Override
public Action[] getActions(Object target, Object sender) {
final Table table = (Table)sender;
// if Table is in multi select mode, getValues() returns Set of item id's
if (table.isMultiSelect() && ((Set)table.getValue()).size() > 1) {
return new Action[] {delete};
} else {
return new Action[] {delete, download};
}
}
...
I see that getActions() is called by the Table component every time a row selection is made. It returns the correct Action array. However, in the UI, only one context menu is used, independent of the actions returned.
This topic is not covered in The Book of Vaadin. There is an old question but the solutions is way too complicated and the solution suggested by Joonas is not working (in fact the case i describe here).
Its a well-known issue in Vaadin from version 6. Most people (including me) work-around this by using ContextMenu Addon
I have an application in which most of the controls are created in code and then added to the layout using AddView method. Does the framework allow binding of ViewModel properties to controls using code or it has to be done in the axml file only?
Alright, after a lot of struggle I finally got the answer.
I had to do the following things.
1) Added an import statement :
using Cirrious.MvvmCross.Binding.BindingContext;
2) Added the following code:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Hello);
TableLayout containerLayout = this.FindViewById<TableLayout>(Resource.Id.containerLayout);
if (containerLayout != null)
{
TableRow newRow = new TableRow(base.ApplicationContext);
newRow.SetMinimumHeight(50);
var txtRace = new EditText(ApplicationContext);
txtRace.Hint = "Race";
var bindingSet = this.CreateBindingSet<HelloView, HelloViewModel>();
bindingSet.Bind(txtRace).To(vm => vm.Race);
bindingSet.Apply();
newRow.AddView(txtRace);
containerLayout.AddView(newRow);
}
}
I already have a "TableLayout" in my HelloView.axml file and all that I am doing in this is creating a new EditText box control (txtRace) and adding it to the view and at the same time binding it to the "Race" property of HelloViewModel object.
I spend a lot of time trying to figure out in what namespace CreateBindingSet() method exists because VS2012 was not giving me any intelliscence on that.
Hope this helps someone facing similar issue.
Yes MvvmCross supports binding properties to controls created at runtime. You can watch this tutorial by the awesome Mr. Stuart in his N+1 series.
http://www.youtube.com/watch?feature=player_embedded&v=cYu_9rcAJU4
Note: He has shown this many a times in the series but I remember this one on the top of my head right now.
I have a page made of custom components. In that page I have a button. If I click the button I have to call another page (page.mxml consisting of custom components). Then click event handler is written in Action-script, in a separate file.
How to make a object of an MXML class, in ActionScript? How to display the object (i.e. the page)?
My code:
page1.mxml
<comp:BackgroundButton x="947" y="12" width="61" height="22"
paddingLeft="2" paddingRight="2" label="logout" id="logout"
click="controllers.AdminSession.logout()"
/>
This page1.mxml has to call page2.mxml using ActionScript code in another class:
static public function logout():void {
var startPage:StartSplashPage = new StartSplashPage();
}
Your Actionscript class needs a reference to the display list in order to add your component to the stage. MXML is simply declarative actionscript, so there is no difference between creating your instance in Actionscript or using the MXML notation.
your function:
static public function logout():void {
var startPage:StartSplashPage = new StartSplashPage();
}
could be changed to:
static public function logout():StartSplashPage {
return new StartSplashPage();
}
or:
static public function logout():void {
var startPage:StartSplashPage = new StartSplashPage();
myReferenceToDisplayListObject.addChild( startPage );
}
If your actionscript does not have a reference to the display list, than you cannot add the custom component to the display list. Adding an MXML based custom component is no different than adding ANY other DisplayObject to the display list:
var mySprite:Sprite = new Sprite();
addChild(mySprite)
is the same as:
var startPage:StartSplashPage = new StartSplashPage();
myReferenceToDisplayListObject.addChild( startPage );
Both the Sprite and the StartSplashPage are extensions of DisplayObject at their core.
You reference MVC in the comments to another answer. Without knowing the specific framework you've implemented, or providing us with more code in terms of the context you are trying to perform this action in, it is difficult to give a more specific answer.
I assume that you are on a page with a set of components and want to replace this set of components on the page with a different set of components. My apologies in advance if this is not what you are trying to do.
You can do this using ViewStacks and switching the selected index on selection -- this can be done either by databinding or by firing an event in controllers.AdminSession.logout() and listening for that event in the Main Page and switching the selectedIndex of the view stack in the handler function.
MainPage.mxml
<mx:ViewStack>
<views:Page1...>
...
<comp:BackgroundButton x="947" y="12" width="61" height="22"
paddingLeft="2" paddingRight="2" label="logout" id="logout"
click="controllers.AdminSession.logout()"/>
</views:Page1...>
<views:Page2 ...>
...
<comp:Comp1 .../>
<comp:Comp2 .../>
</views:Page2>
I think you may use state to do you work.
You may take a look at http://blog.flexexamples.com/2007/10/05/creating-view-states-in-a-flex-application/#more-221
Edit:
I am not sure I fully understand your case.
As I know, you may make a new state in page1.mxml, and name it, eg. secondPageState, and then put the custom component page2.mxml in the secondPageState.
In the controller, you need an import statement to import the page1 component and make a public var for the page1 component, eg. firstPage.
Then, the code will similar to:
public function logout():voild
{
firstPage.currentState = "secondPageState";
}
Another solution:
If you don't like the change state solution, you may try to use the addchild, to add the custom component to your application.