I have a ComboBox called projectRequirementComboBox that is dependent from projectComboBox, from where I get the list to show in the dropdown in projectRequirementComboBox, but I want to do something like: when a user changes the project I want to empty projectRequirementComboBox, to be more clear none of the item will not be selected I am doing this right now but still my projectRequirementComboBox has the old value, I don't know what am I missing .I am using vaadin.version 8.0.7 .
private void refreshProjectRequirementCombobox()
{
List<ProjectRequirement> projectRequirements = new ArrayList<>();
if (projectComboBox.getValue() != null)
{
projectRequirements = projectRequirementService.findCurrentProjectRequirements(projectComboBox.getValue().getProjectId());
}
projectRequirementComboBox.setItems(projectRequirements);
projectRequirementComboBox.setValue(null);
}
private void loadProjectRequirement(Project project)
{
List<ProjectRequirement> projectRequirements = new ArrayList<>();
if (project != null)
{
projectRequirements = projectRequirementService.findCurrentProjectRequirements(project.getProjectId());
}
projectRequirementComboBox.setItems(projectRequirements);
}
I call refreshProjectRequirementCombobox here.
projectComboBox.addValueChangeListener(event ->
{
refreshProjectRequirementCombobox();
loadRejectReason();
});
Normally this should work. I created a minimum example with two ComboBoxes "main" and "dependent". The selection of the dependent ComboBox depends on the selection of the main ComboBox. Therefore there is a ValueChangeListener on the main ComboBox that resets the items and the selected value of the dependent ComboBox. When you start the application you see that the offered items of the dependent ComboBox change and that none of these new items is selected.
I think you have to post more of your code (where do you call refreshProjectRequirementCombobox from?) to see what you are doing different.
Here is my example minimum project code:
#Override
protected void init(VaadinRequest vaadinRequest) {
final VerticalLayout layout = new VerticalLayout();
final ComboBox<String> main = new ComboBox<>();
final ComboBox<String> dependent = new ComboBox<>();
final Map<String, String[]> dependentsByMain = new HashMap<>();
dependentsByMain.put("A", new String[]{"AA", "AB", "AC"});
dependentsByMain.put("B", new String[]{"BA", "BB", "BC"});
dependentsByMain.put("C", new String[]{"CA", "CB", "CC"});
List<String> mainItems = new ArrayList<>(dependentsByMain.keySet());
main.setItems(mainItems);
dependent.setItems(Arrays.asList("Test1", "Test2", "Test3"));
dependent.setValue("Test1");
main.addValueChangeListener((HasValue.ValueChangeListener<String>) valueChangeEvent -> {
if (valueChangeEvent.getValue() != null) {
dependent.setItems(dependentsByMain.get(valueChangeEvent.getValue()));
dependent.setValue(null);
}
});
layout.addComponents(main, dependent);
setContent(layout);
}
UPDATE:
Have a look at Srinivasan Sekar's answer and its comments. This is a bug in the used version (8.0.7) which seems to be fixed in version 8.5 (according to https://github.com/vaadin/framework/issues/9047#issuecomment-437864866). I tried my example code with version 8.7.1 so it works. With version 8.0.7 it doesn't.
So the main solution is to update the used Vaadin version. As a workaround (when unable to upgrade the Vaadin version) you FIRST have to set the ComboBox's value to null and THEN set the new items. So in my example the ValueChangeListener must look like:
main.addValueChangeListener((HasValue.ValueChangeListener<String>) valueChangeEvent -> {
if (valueChangeEvent.getValue() != null) {
dependent.setValue(null);
dependent.setItems(dependentsByMain.get(valueChangeEvent.getValue()));
}
});
There is open issue in Vaadin https://github.com/vaadin/framework/issues/9566 which refers to https://github.com/vaadin/framework/issues/2813
Going through the issue I found that by creating a custom combobox you can fix the issue:
public class ClearableComboBox<T> extends ComboBox<T> {
public ClearableComboBox(String in) {
super(in);
}
protected void setSelectedFromServer(T item) {
String key = itemToKey(item);
T oldSelection = getSelectedItem().orElse(getEmptyValue());
doSetSelectedKey(key);
fireEvent(new SingleSelectionEvent<>(ClearableComboBox.this, oldSelection, false));
}
}
Additionally, make sure to call setValue before calling setItems to clear items.
cmb.setValue(null);
cmb.setItems(aEmptyCollection);
Related
I created a TableTree that contains object of class Component that has a boolean property "selected".
I want to hide the rows from the table where the rows component is not selected.
I tried this:
componentTree.setRowFactory(new Callback<TreeTableView<Component>, TreeTableRow<Component>>() {
#Override
public TreeTableRow<Component> call(TreeTableView<Component> param) {
TreeTableRow<Component> row = new TreeTableRow<Component>() {
#Override
protected void updateItem(Component component, boolean empty) {
if(!empty) {
if (!component.isSelected()) {
setVisible(false);
setManaged(false);
System.out.println("hide");
} else {
setVisible(true);
setManaged(true);
System.out.println("show");
}
}
}
};
return row;
}
});
On system.out I can see a lot of "show" and "hide" messages, but this doesn't affect the table, all rows are shown as before.
Any idea on this topic?
Thanks!
I used eclipse's fx.ui.controls library for the same achieve the same goal before.
<dependency>
<groupId>at.bestsolution.eclipse</groupId>
<artifactId>org.eclipse.fx.ui.controls</artifactId>
<version>2.2.0</version>
</dependency>
The library provides a class: FilterableTreeItem<T> under the tree package. This class was designed to be used in cases like yours. You can provide a Predicate to the root of the tree and the items will get hidden when the value given changes:
// Children
final FilterableTreeItem<Component> childNode1 = new FilterableTreeItem<>(component1);
final FilterableTreeItem<Component> childNode2 = new FilterableTreeItem<>(component2);
final FilterableTreeItem<Component> childNode3 = new FilterableTreeItem<>(component3);
// Root
final FilterableTreeItem<Component> root = new FilterableTreeItem<>(rootComponent);
root.getInternalChildren().setAll(childNode1, childNode2, childNode3);
root.setPredicate((parent, value) -> value.isSelected());
// TreeTableView
final TreeTableView<Component> treeTableView = new TreeTableView<>(root);
Note that you have to use getInternalChildren() to add children and the default getChildren().
FilterableTreeItem<T> also provides a predicateProperty() that you can bind to another property in case you need to update the how items are shown or hidden.
Another advatage of this class is that it shows the whole path up to the root of the items matching that predicate.
I need to update the list of a ListSelect after i click in one button but i dont know how to
Here is my code:
Create List Method
private void createListPanel() {
VerticalLayout listPanel = new VerticalLayout();
listPanel.setWidth(100f, Unit.PERCENTAGE);
queryList= new ListSelect("List Of Querys", getQueryList());
queryList.setWidth(100f, Unit.PERCENTAGE);
queryList.setNullSelectionAllowed(false);
queryList.addValueChangeListener(event -> {
selectedQuery = (String) (queryList.getValue());
String retrievedQuery = repository.getRawQuery(selectedQuery);
});
listPanel.addComponent(queryList);
panelSuperior.addComponent(listPanel);
}
getQueryList()
private List<String> getQueryList() {
return repository.getQueryNames();
}
Create Button Method
private void CreateButton() {
Button buttonRefresh= new Button("Refresh");
buttonRefresh.addClickListener((Button.ClickEvent e) -> {
// i tried this
queryList.setContainerDataSource((Container) getQueryList());
});
buttonPanel.addComponent(button);
}
I tried this line at CreateButton() method:
queryList.setContainerDataSource((Container) getQueryList())
but i get a
java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.vaadin.data.Container
because this method need a Container Object
I was searching in the Vaadin javadoc but I am not able to find a method to set or update the list of the ListSelect
Vaadin Javadoc: Vaadin Javadoc 7.7.9 ListSelect
Thanks in advance
The straightforward way is to remove all items from an underlying container and add new items afterward:
Container container = queryList.getContainerDataSource();
container.removAllItems();
List<String> queries = getQueryList();
for(String query : queries) {
container.addItem(query);
}
ListSelect(String caption, Collection<?> options) constructor creates an IndexedContainer and populates it with items from your collection.
Another option is to bind ListSelect to a container which could possibly enable it to track changes automatically. For more on this, see "Collecting Items in Containers" topic from Vaadin docs.
I have problem with my TableView element. I adding listener like that:
HardwareIdTableView.getItems().addListener(
(ListChangeListener.Change<? extends FirmwareData.HardwareIdWrapper> change) -> {
checker.hardwareIdCompleted.setValue(change.getList().size() > 0);
});
checker.hardwareIdCompleted is BooleanProperty.
I checked in debugger and new items was added to the TableView, but hardwareIdCompleted still resist 'false'.
P.S.
I add items to TableView like this:
public void addHardwareKey(HardwareIdKeyT key) {
ObservableList<FirmwareData.HardwareIdWrapper> idKeys = HardwareIdTableView.getItems();
if (idKeyEditSelected != null) {
fwData.removeHardwareIdKey(idKeyEditSelected.getIdPattern());
idKeys.remove(idKeyEditSelected);
}
if (!idKeys.contains(key)) {
HardwareIdTitledPane.pseudoClassStateChanged(PseudoClass.getPseudoClass("pane-error"), false);
idKeys.add(new FirmwareData.HardwareIdWrapper(key));
fwData.addHardwareIdKey(key);
}
}
The fault was straight - my reset function assigned new list to TableView. Since listener was assigned to old item list, it doesn't get notification, when I was expecting.
I have a List, that included JPA Entity objects of a certain type. Their reference String values are displayed in a JList for the user to see.
I want my user to be able to select filters as JCheckBoxes in the UI such as 'only from Client x', or 'only of Type x' and dynamically filter the Entity List.
I had thought to just keep a copy of static List completeList; and static List filteredList; and then just run individual filter methods each time a new filter is selected in the UI to update filteredList, which would work fine until you have to un-select a single filter and leave the others selected (at which point it all falls apart).
Every situation I think through fall apart at one point or another, usually when trying to select multiple filters of from one Menu.
An example of my thought pattern that checks all the filters to determine what needs to go in the new JList;
public static void filterList(){
List filteredList = new ArrayList<Job>(StoredDataClass.completeList);
if(clientSmithsCheckBox.isSelected()){
for(Job job : filteredList){
if(!job.getClient.equals(clientSmithsCheckBox.getText())){
filteredList.remove(job);
}
}
}
....... // Check other filters here etc.
if(clientBobAndCoCheckBox.isSelected()){
for(Job job : filteredList){
if(!job.getClient.equals(clientBobAndCoCheckBox.getText())){
filteredList.remove(job);
}
}
}
Even if clientBobAndCoCheckBox is selected, no jobs with that client will show in the final list, because we already removed them all because another client was already selected. Now, we could add to the list instead but we would face similar problems of having add stuff that shouldn't be there etc.
This is obviously possible, because this type of filtering system is common practice (example, excel). Although this is more of a design question, how can I achieve this?
Here's a short (and raw!) example of how you could organize your logic. It's in the context of SwingX (which supports sorting/filtering of a JList just the same way as a JTable) because I'm lazy - but you can apply it to your own environment easily.
Think of your criteria as a collection of filters which can be on or off, and then combine them with OR (if one or more is selected) or turn off if none is selected. The sole "trick" is to evaluate all of the checkboxes' states wheneven one of them is changed:
final JXList list = new JXList(new DefaultComboBoxModel(Locale.getAvailableLocales()));
list.setAutoCreateRowSorter(true);
final List<RowFilter> filters = new ArrayList<>();
filters.add(new MyRowFilter("de"));
filters.add(new MyRowFilter("ar"));
final List<JCheckBox> boxes = new ArrayList<>();
ActionListener l = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
List<RowFilter<Object, Object>> orCandidates = new ArrayList<>();
for (int i = 0; i < boxes.size(); i++) {
if (boxes.get(i).isSelected())
orCandidates.add(filters.get(i));
}
RowFilter<Object, Object> or = orCandidates.isEmpty() ? null :
RowFilter.orFilter(orCandidates);
list.setRowFilter(or);
}
};
JCheckBox first = new JCheckBox("de");
first.addActionListener(l);
boxes.add(first);
JCheckBox second = new JCheckBox("ar");
second.addActionListener(l);
boxes.add(second);
JComponent content = new JPanel();
content.add(new JScrollPane(list));
for (JCheckBox box : boxes) {
content.add(box);
}
showInFrame(content, "filters");
// just for completeness, the custom RowFilter
public static class MyRowFilter extends RowFilter {
private String text;
public MyRowFilter(String text) {
this.text = text;
}
#Override
public boolean include(Entry entry) {
Locale locale = (Locale) entry.getValue(0);
return locale.getLanguage().contains(text);
}
}
I have a GXT 3 TabPanel and would like to disable one or more tabs in response to an event.
There does not seem to be a way to do this.
PlainTabPanel panel = new PlainTabPanel();
TabItemConfig config = new TabItemConfig("Disabled");
Label disabled = new Label("This tab should be disabled");
config.setEnabled(false); // here what you need
panel.add(disabled, config);
I figured this out a while back and forgot to post the answer. Here's a way to do this that works reliably :
public class SimpleTabPanel extends com.sencha.gxt.widget.core.client.PlainTabPanel
implements TabPanel {
Tab currentActiveTab;
private Map<SimpleTab,TabItemConfig> tabConfigs = new HashMap<SimpleTab,TabItemConfig>();
// a map sorted by priority used to keep the expected tab order
SortedMap<TabData, SimpleTab> tabsConfig = new TreeMap<TabData, SimpleTab>(
new Comparator<TabData>() {
#Override
public int compare(TabData o1, TabData o2) {
return Float.compare(o1.getPriority(), o2.getPriority());
}
});
#Override
public Tab addTab(TabData tabData, String historyToken) {
SimpleTab newTab = createNewTab(tabData);
tabsConfig.put(tabData, newTab);
newTab.setTargetHistoryToken(historyToken);
return newTab;
}
private void disableTab(SimpleTab tab, TabData key){
// get and save tab's config.
TabItemConfig tic = getConfig(tab);
tabConfigs.put(tab, tic);
// put new one on tab to disable it.
tic = new TabItemConfig(key.getLabel());
tic.setEnabled(false);
update(tab, tic);
}
public void enableAllTabs(){
for(TabData key : tabsConfig.keySet()){
SimpleTab tab = tabsConfig.get(key);
TabItemConfig tic = tabConfigs.get(tab);
if(tic!=null){
tic.setEnabled(true);
update(tab, tic);
}
}
}
}
I had the same issue happening in my project.
The way I solved it is really simple and I hope that it answers your need.
public void enableTab(IsWidget item, Boolean enable) {
TabItemConfig config = tabPanel.getConfig(item.asWidget());
config.setEnabled(enable);
tabPanel.update(item.asWidget(), config);
}
I call that method every time I need to change a tab state.