Cannot link text field to RowItem from SQLContainer with Vaadin - java

I'm building a simple CRUD application with a MySql database as back end. So far I managed to link a grid to the contents of a SQLContainer with the FreeformQuery (so the read is fine).
String query = "select a.id, a.name name, b.name type from asset a join " +
" assettype b on a.assettype_id = b.id";
grid.setContainerDataSource(container);
For the container the SQLContainer. I created a form and I did the binding between its contents and a selected row
grid.addSelectionListener(event -> {
if (event.getSelected().isEmpty()) {
form.setVisible(false);
} else {
Item item = container.getItem(event.getSelected().iterator().next());
form.setAsset(item);
}
});
So, as you see, the form is linked to an Item. setAsset is simply a form method that links the row contents to the text fields of the form.
public void setAsset(Item item) {
this.item = item;
FieldGroup binder = new FieldGroup(this.item);
binder.bind(textField1, "name");
binder.bind(textField2, "type");
setVisible(true);
}
Well, I don't know anymore how to add a row, or how to edit an existing one. For editing a row I tried with a save method for the form (that I call with a button) as follows
private void save() throws UnsupportedOperationException, SQLException {
SQLContainer container = db.getContainer();
container.addItem(item);
container.commit();
}
Well, problem one is that, if I select a grid item, I see the contents of name and type in the text fields but, if I modify their values in the text field before entering the save method, this.item still has the original values (when I thought it would take the new value in the text field because the textfields are bound to the RowItem). Does anybody know what's going on?
In addition, if I want to create a new row, I would like to have something like this
Button createAsset = new Button("Add asset");
createAsset.addClickListener(e ->
{
grid.select(null);
form.setAsset(new Item());
});
and fill the contents of the blank Item() in the form, before pushing it to the table. Of course I can't because Item and RowItem are interfaces. So how can I instantiate an empty row of a container before filling its contents?
Thanks very much in advance.

In the end, I would say that either I din't use the FieldGroup.bind method properly, or that there is a bug in it. This is my original entry
public void setAsset(Item item) {
this.item = item;
FieldGroup binder = new FieldGroup(this.item);
binder.bind(textField1, "name");
binder.bind(textField2, "type");
setVisible(true);
}
which did not work, and this is what works (which to me, is the same)
public void setAsset(Item item) {
this.item = item;
textField1.setPropertyDataSource(item.getItemProperty("name"));
textField2.setPropertyDataSource(item.getItemProperty("type"));
setVisible(true);
}

Related

Select JTree node from JComboBox and vice versa

I have JTree and JComboBox in my application. When I select a node, JComboBox content also changes, but I need to do same thing in case of selecting JComboBox item.
As you see, if I select "Default Session Start" , the same node should be selected in the JTree. Could someone tell me, what will be a good approach for it. enter image description here
This is just a part of a skeleton of an application. Swing is rather verbose, and much you'll need to work out. You provide data models for the JComponents, and need to add listeners, or
JComboBox<Thing> comboBox = new JComboBox<>(controller.getComboBoxModel());
JTree tree = new JComboBox<>();
... tree.setSelectionModel(controller.getTreeSelectionModel());
publi class Controller { // or Application
public static void main(String[] args) { ... }
// Model:
private ComboBoxModel<Thing> comboBoxModel;
private TreeSelectionModel treeSelectionModel;
public Controller() {
comboBoxModel = new DefaultComboBoxModel() {
#Override
pubic void setSelectedItem​(Thing item) {
if (!item.equals(getSelectedItem())) {
super.setSelectedItem(itenm);
treeSelectionModel.setSelectionPath(...);
}
}
};
treeSelectionModel = new DefaultTreeSelectionModel ...
...
}
Important is that there is no back-and-forth setting the selected item, for an unchanged item. Hence the equality test.

ComboBoxItem not showing selected item smartgwt

i've a simple combobox item contained in a Dynamicform made with smartgwt. I've populated the dropdown list with the resultset of some query to the database and it is correctly populated. Then I've set some handler to manage the fact that the combobox is populated based on an other combobox of the for, and it is specifically an onFocus Handler which gives the message to populate at first the first required combo and only then the file combo (the combo in question). The problem is that now i have the populated list and the onfocus event without errors but i cannot select anything in the combo cause whatever i select the row of the selection always remains empty.
This is weird, i don't even get any error in development mode to see if something is wrong.
I'm pasting the code of the combo:
fileComboBox.addFocusHandler(new FocusHandler(){
#Override
public void onFocus(FocusEvent event){
String society = (String) getCompany();
if(society==null || society.equals(EMPTY_STRING)){
SC.say(constants.selezionaSocieta());
}
companyComboBox.focusInItem();
}});
fileComboBox.setTitle(constants.fileUploadMov());
fileComboBox.setName(FILE);
fileComboBox.setValueField(TestataDS.ATTR_ID_UPLOAD);
fileComboBox.setDisplayField(TestataDS.ATTR_NOME_FILE);
fileComboBox.setAutoFetchData(false);
fileComboBox.setFetchMissingValues(false);
fileComboBox.setOptionDataSource(TestataDS.getInstance());
fileComboBox = new ComboBoxItem() {
#Override
protected Criteria getPickListFilterCriteria() {
return getFileCriteria();
}};
public AdvancedCriteria getFileCriteria(){
String society = (String) getCompany();
String societyValue = ( society != null) ? society : "";
Criterion cSociety = new Criterion("codSocGest", OperatorId.EQUALS, societyValue);
return new AdvancedCriteria(OperatorId.AND, new Criterion[]{cSociety});
}
I solved it turning the combobox into a selectItem

Wicket ajax call does not render my new component

hope you can help me with this because it has been bugging me for a few days now.
I have a wicket DataTable filled with 16 columns. Every row can have some child info (if it has a '+' button is shown in the first cell). Since the child info is just some regular text with a date on when it was entered, I did not want to use a real TreeData object. I have been trying to make the '+' button into an AjaxFallbackButton, which works, but my child data is rendered inside the first cell of the row, which is very impractical.
I am now trying to dynamically create a new row by prepending some JS on the target:
target.prependJavaScript(String.format("var item=document.createElement(\"tr\"); item.id=\"%s\"; $(\"#%s\").after(item);", newChild.getId(), rowId));
This is great because it actually creates a new tag inside my page. But how do I get my new data inside this newly rendered HTML? I guess my problem is that Wicket does not 'know' the new row and if I add the new wicket Item (the container in Wicket with the new row) to the Wicket DataTable and add the body of the DataTable to the target then now rendering of my new row is done.
My markup for the page:
[table]
My custom DataTable extension Java code (extended to make sure all outputMarkUp is added):
#Override
protected void onInitialize() {
super.onInitialize();
this.addTopToolbar(new NavigationToolbar(this));
this.addTopToolbar(new HeadersToolbar<>(this, (ISortableDataProvider)this.getDataProvider()));
this.addBottomToolbar(new NoRecordsToolbar(this));
this.setOutputMarkupId(true);
}
#Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(CssReferenceHeaderItem.forReference(WarehouseToolbarCssReference.get()));
}
#Override
protected Item<T> newRowItem(String id, int index, IModel<T> model) {
Item<T> item = super.newRowItem(id, index, model);
this.lastId = Integer.valueOf(id);
item.setMarkupId(this.getId() + item.getId());
return item;
}
The first column uses a custom Panel to fill up the cells in the column, but after a lot of tries and tests, I'm actually ending up with the regular Node from Wicket itself:
<wicket:panel xmlns:wicket="http://wicket.apache.org">
<a wicket:id="junction"></a>
<span wicket:id="content" class="tree-content">[content]</span>
cellspacing="0" wicket:id="reasonData">[Reason data]</table>-->
</wicket:panel>
And finally the code that creates the new row and fills up the necessary data (which is itself a new DataTable) and also fills the ajax-target:
public void onClick(AjaxRequestTarget target) {
Integer currentRowIndex = Integer.valueOf(this.findParent(Item.class).findParent(Item.class).getId());
String rowId = this.findParent(Item.class).findParent(Item.class).getMarkupId();
Item<IColumn<OldOrder, String>> newChild = null;
this.dataTable.setVisible(true);
newChild = new Item<>(String.valueOf(this.findParent(DataTable.class).getLastId() + 1), currentRowIndex * -1, null);
newChild.setOutputMarkupId(true);
target.prependJavaScript(String.format("var item=document.createElement(\"tr\"); item.id=\"%s\"; $(\"#%s\").after(item);", newChild.getId(), rowId));
this.populateChildRow(newChild); // This is where the new row gets filled with the new data
Component rows = this.findParent(DataTable.class).getBody().get("rows");
if (rows instanceof WebMarkupContainer) {
((WebMarkupContainer)rows).add(newChild);
}
target.add(this.findParent(DataTable.class).getBody());
}
// This is where the new row gets filled with the new data
private void populateChildRow(Item<IColumn<ParentClass>, String>> item) {
RepeatingView cells = new RepeatingView("cells"){
#Override // Overridden to check if this gets executed... it doesn't
protected void onAfterRender() {
super.onAfterRender();
String stop = "STOP";
}
};
item.add(cells);
Item<?> cellItem = new Item<>("arbitrary", 1, null);
cells.add(cellItem);
cells.setVisible(false);
cells.setOutputMarkupId(true);
cells.add(AttributeAppender.append("colspan", this.findParent(DataTable.class).getColumns().size()));
this.dataTable.setOutputMarkupId(true);
cellItem.add(this.dataTable); // The DataTable with the child data
}
Besides the fact I should clean out some code, the child data is never rendered. Can someone please shed some light on this?
I'd suggest to go with JavaScript all the way, i.e. create a new <tr> and then populate it with JS. Don't use Wicket's Item at all.
When the expand link is clicked do something like target.appendJavaScript("yourOwnFunction('"+link.getMarkupId()+"', "+someDataAsJson+")");. So yourOwnFunction() will use the link id to find its closest parent <tr> and then with JS you can append the new row after it. Once you have the row created you could use the JSON with the data to populate it as you need.

How to make only some columns editable in a Vaadin Grid?

Vaadin Grid allows to be defined as editable with
grid.setEditorEnabled(true);
This makes all visible columns editable. However I don't want the user to edit an specific column, but seems like the editable is an all or nothing.
The next best solution I have found is to define an editor field with a disabled editor, which almost does the trick but the user is still able to select the text and move the cursor (but the field is not editable anymore).
Grid.Column nameColumn = grid.getColumn("fullName");
nameColumn.setHeaderCaption("Full Name");
nameColumn.setEditorField(getNoEditableTextField());
...
private Field<?> getNoEditableTextField() {
TextField noEditableTextFiled = new TextField();
noEditableTextFiled.setEnabled(false);
return noEditableTextFiled;
}
I believe Label cannot be used because it's not a Field.
Is there a better option to achieve this?
edit: as aakath said, there is a way of achieving this not enabling the column to be edited, but in doing so the cell value disappears when you edit the row, which is not desirable.
Did you try calling setEditable(false) method on the column? I believe it should make the field non-editable when the item editor is active.
grid.getColumn("fullName").setEditable(false);
my solution is below. i have just finished. it was not tested too much. but it may give you some ideas.
ati
getColumn(columnName).setEditable(true).setEditorField(getNoEditableField(columnName));
...
private Field<?> getNoEditableField(final String columnName) {
CustomField<Label> result = new CustomField() {
#Override
protected Component getContent() {
Label result = (Label) super.getContent();
Object editedItemId = getEditedItemId();
String value = DEFAULT_VALUE;
if (editedItemId != null) {
value = CustomizableGrid.this.toString(getContainerDataSource().getItem(editedItemId).getItemProperty(columnName).getValue());
}
result.setValue(value);
return result;
}
#Override
protected Component initContent() {
Label result = new Label(DEFAULT_VALUE, ContentMode.HTML);
result.setDescription(getColumnDescription(columnName));
result.setStyleName("immutablegridcellstyle");
return result;
}
#Override
public Class getType() {
return Label.class;
}
};
result.setConverter(new Converter<Label, Object>() {
//converter for your data
});
return result;
}
I had the same problem and didn't want that clicking on id column opens editor. I solved it with adding an ItemClickListener as below. It works fine for me.
grid.addItemClickListener((ItemClickListener<GridBean>) event -> grid.getEditor().setEnabled(!event.getColumn().getCaption().equals("Id")));
Also byc clicking on specific columns Grid is not editable any more.
There is one tricky way to do it! I've just found out it.
So, first of all you need to use grid with container, instead of direct rows adding:
BeanItemContainer<MyBean> container = new BeanItemContainer<>(MyBean.class);
setContainerDataSource(container);
Then remove fields setters from MyBean, except setters for fields what you have to edit.
I think the same can be achieved by making the grid an editable one by grid.setEditorEnabled(true); and disabling editing option for other columns like grid.getColumn(columnName).setEditable(false);. But I am not sure of any demerits of this method. Any suggestion is always appreciated.
Its simple just go to Vaadin Documentation what did from it is below:
you can see here I gave a specified column Name
grid = new Grid<>();
lst = new ArrayList<>();
provider = new ListDataProvider<>(lst);
lst.add(new Company(1, "Java"));
grid.setDataProvider(provider);
grid.addColumn(Company::getSerialNo).setCaption("Sr.no");
TextField tf = new TextField();
grid.getEditor().setEnabled(true);
HorizontalLayout hlyt = new HorizontalLayout();
grid.addColumn(Company::getName).setEditorComponent(tf, Company::setName).setCaption("Name").setExpandRatio(2);
hlyt.addComponent(grid);
I use the following approach to get a read-only field, the trick is override the setEnabled method to get a disabled textfield. If you trace the source code in Vaadin Grid, no matter what field you pass to a Grid, it will always call the field.setEnabled(true).
myGrid.getColumn(propertyId).setEditorField(new ReadOnlyField());
And
public class ReadOnlyField extends TextField
{
public ReadOnlyField()
{
super();
this.setReadOnly(true);
}
#Override
public void setEnabled(boolean enabled)
{
// always set to disabled state
super.setEnabled(false);
}
}

Prevent some values of SmartGWT IPickTreeItem to be selected

I'm trying to clear the user selected value on a IPickTreeItem.
This is the only solution I've found to restrict the user from selecting some of the Tree root values (not all).
To be more clear, it seems that calling event.cancel() do not stop the event from bubbling.
Am I doing something wrong ?
TreeNode treenode = new TreeNode("root", new TreeNode("Operation A"),
new TreeNode("Operation B"));
final DynamicForm dynamicForm = new DynamicForm();
Tree tree = new Tree();
tree.setRoot(treenode);
final IPickTreeItem pickTreeItem = new IPickTreeItem();
pickTreeItem.setValueTree(tree);
pickTreeItem.addChangeHandler(new ChangeHandler()
{
#Override
public void onChange(ChangeEvent event)
{
pickTreeItem.clearValue() // Not clearing the value
pickTreeItem.setValue((String)null) // Not working neither
event.cancel() // Not seeming to work...
}
});
dynamicForm.setItems(pickTreeItem);
dynamicForm.draw();
This is not working either :
pickTreeItem.setInputTransformer(new FormItemInputTransformer()
{
#Override
public Object transformInput(DynamicForm form, FormItem item,
Object value, Object oldValue)
{
return "Desired New Value (not working)...";
}
});
This is weird because it works using an external Button to clear the value (outside the picktreeitem handler)
Button bt = new Button("click");
bt.addClickHandler(new ClickHandler()
{
#Override
public void onClick(ClickEvent event)
{
pickTreeItem.setValue((Object) null);
}
});
Expected behavior
My Tree :
-aaaa
----bbbb
----cccc
-dddd
----eeee
----ffff
If the user selects "aaaa" the PickTreeItem value should be reverted to the defaultValue ("Choose a value"), optionally inform the user that he cannot pick "aaaa".
The PickTreeItem should accept "dddd" as a valid choosen value.
As with all FormItems, event.cancel() is the correct way to disallow the change. There was a framework level bug that was preventing this from behaving correctly that has now been corrected.
See this thread on the Isomorphic forums
I understand it is not exactly the same with what you are trying to achieve, but you could consider to define a CustomValidator, that reads the selected values and returns false and an appropriate message, when one of the parent values that shouldn't be, is selected. For this to work, you must set pickTreeItem.setCanSelectParentItems(Boolean.TRUE), to allow for parent items to be selected, and pickTreeItem.setValidateOnChange(Boolean.TRUE), to validate the selected values upon selection.

Categories