Selecting a listbox dropdown item in GWT - gwt

I have a GWT view from which I grab the value of a dropdown and store it in a DB. The dropdown has the values "one" "two" "three". When I go back to the same view and I have "Two" stored in the DB then I want "Two" to be the selected item. However the only way I can get this to work at the moment is by iterating through each item in the listbox to find the one which matches and then set this as the selected one. Is there a better way to achieve this? I don't want to have to save the selected index.

I recommend you to extend ListBox and implement TakesValue interface. And in this class maintain a list variable which holds all the items in the ListBox. setValue and getValue should looks like the following code snippet -
private List<String> listItems = new ArrayList<String>();
public class MyListBox extends ListBox implements TakesValue<String>
{
public void setValue( String value )
{
if ( listItems.size() > 0 )
{
int valueIndex = 0;
if ( listItems.contains( value ) )
{
valueIndex = listItems.indexOf( value );
this.value = value;
}
setItemSelected( valueIndex, true );
}
}
public String getValue()
{
int selectedIndex = super.getSelectedIndex();
String value = null;
if ( selectedIndex >= 0 )
{
value = super.getValue( selectedIndex );
if ( "null".equals( value ) )
{
value = null;
}
}
return value;
}
public void setOptions(List<String> options)
{
listItems.clear();
listItems.addAll( items );
for ( String item : listItems )
{
addItem( item, item );
}
}
}
Now its just a matter of doing listBox.setValue( value ) method call from the view java file. Prior to this options must be set.

Related

Make focus go to next entry in a collection view

I have an application in .Net Maui that uses a collection view with an entry field and after the collection view one static entry field. If you are currently focused on the first entry in the collection view and hit tab or enter it will not navigate to the next entry in the collection view and focus on the static entry field. I need to find the best way to have the entry focus on the next entry in the collection view on complete.
I have tried changing the return type of the collection view entry field to Next and also tried the community toolkit SetFocusOnEntryCompletedBehavior function and both result in the same behavior of not navigating to the next entry from the collection view. Very similar to this issue that doesnt seem to be resolved. MAUI - CollectionView jump / focus to next entry
I found a workaround for you. You could try the following code:
Step1 Create a custom control , let's call it MyEntry (MyEntry.cs) which subclass Entry:
In this control we attach a BindableProperty IsExpectedToFocusProperty which we used it to judge whether it is goning to be focused. We also registered a new method OnIsExpectedToFocus to detect propertyChanged for our control. For info about BindableProperty, you could refer to Bindable properties.
MyEntry.cs,
public class MyEntry : Entry
{
public static readonly BindableProperty IsExpectedToFocusProperty = BindableProperty.Create("IsExpectedToFocus", typeof(bool), typeof(MyEntry), false, propertyChanged:OnIsExpectedToFocus);
public bool IsExpectedToFocus
{
get => (bool)GetValue(IsExpectedToFocusProperty);
set => SetValue(IsExpectedToFocusProperty, value);
}
static void OnIsExpectedToFocus(BindableObject bindable, object oldValue, object newValue)
{
// Property changed implementation goes here
if ((bool)newValue == true)
{
(bindable as Entry).Focus();
}
}
}
Step2 Consume custom control in CollectionView. We define the ReturnCommand and its parameter. we will bind them in the MainPageViewModel.
MainPage.xaml,
<CollectionView x:Name="mycoll" ItemsSource="{Binding ItemCollection}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<local:MyEntry x:Name="myentry" Focused="myentry_Focused"
IsExpectedToFocus="{Binding IsExpectedToFocus}"
Text="{Binding Title,Mode=TwoWay}" TextColor="Black"
ReturnCommand="{Binding Source={RelativeSource AncestorType={x:Type local:MainPageViewModel}}, Path=ReturnCommand}"
ReturnCommandParameter="{Binding .}"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
In .cs file:
void myentry_Focused(System.Object sender, Microsoft.Maui.Controls.FocusEventArgs e)
{
var entry = sender as Entry;
foreach (var item in viewModel.ItemCollection)
{
if (entry.BindingContext != item)
{
item.IsExpectedToFocus = false;
}
}
}
Step3 Design our MainPageViewModel. I define an ObservableCollection which ItemSource will bind to. And add three items just for test.
Then I think the most important part is to design the Command. Let me explain it briefly. When we press the entry of an Entry, we fire the ReturnCommand and get current Item through ReturnCommandParameter. We get the index of current Item in ItemCollection. So the next entry which needs to be focused corresponds to the index+1 Item. Then we changed the IsExpectedToFocus of the next entry and fire the OnIsExpectedToFocus method which set the entry be focused. Done!
MainPageViewModel.cs
public class MainPageViewModel
{
public ObservableCollection<Item> ItemCollection { get; set; } = new ObservableCollection<Item>();
public Command ReturnCommand
{
get
{
return new Command<Item>((e) =>
{
e.IsExpectedToFocus = false;
int index = ItemCollection.IndexOf(e); // get the current index
if (index != -1)
{
int nextIndex;
// if last entry, next index is 0, else index +1
if (index < (ItemCollection.Count() - 1))
{
nextIndex = index + 1;
ItemCollection[nextIndex].IsExpectedToFocus = true;
}
else if(index == (ItemCollection.Count() - 1))
{
nextIndex = 0;
ItemCollection[nextIndex].IsExpectedToFocus = true;
}
}
});
}
}
public MainPageViewModel()
{
//add three item for test
ItemCollection.Add(
new Item
{
Title = "12345",
IsExpectedToFocus = false
}) ;
ItemCollection.Add(
new Item
{
Title = "23456",
IsExpectedToFocus = false
});
ItemCollection.Add(
new Item
{
Title = "34567",
IsExpectedToFocus = false
});
}
}
Also, this is Item.cs, should implement INotifyPropertyChanged
public class Item : INotifyPropertyChanged
{
public string title;
public bool isExpectedToFocus;
public string Title
{
get
{
return title;
}
set
{
title = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
}
}
public bool IsExpectedToFocus
{
get
{
return isExpectedToFocus;
}
set
{
isExpectedToFocus = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsExpectedToFocus)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Hope it works for you.

How can I use an extended entity to create a new property in my EF6 class with property changed notification?

I have a table in my entity model called prices. It has several fields named value0, value1, value2, value3, value4... (these are their literal names, sigh..). I cannot rename them or in any way change them.
What I would like is to use an extended entity to create a new property called values. This would be a collection containing value1, value2 etc...
To get access to the values I would then simply need to write prices.values[1]
I need property changed notification for this.
So far I have tried this;
public partial class Prices
{
private ObservableCollection<double?> values = null;
public ObservableCollection<double?> Values
{
get
{
if (values != null)
values.CollectionChanged -= values_CollectionChanged;
else
values = new ObservableCollection<double?>(new double?[14]);
values[0] = value0;
values[1] = value1;
values[2] = value2;
values.CollectionChanged += values_CollectionChanged;
return values;
}
private set
{
value0 = value[0];
value1 = value[1];
value2 = value[2];
}
}
private void values_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Values = values;
}
}
The issue comes when trying to set values. if I try to set a value by writing
prices.values[0] = someValue;
The new value is not always reflected in the collection (i.e. when I have previously set value and then try to overwrite the value).
I am willing to try any approach that would achieve my goal, I am not precious about having my solution fixed (although if anyone can explain what I'm missing that would be great!)
You could implement an indexer on Prices class without using a collection.
You can use switch to select the property to write or you can use reflection.
In this case I use reflection.
public double? this[int index]
{
get
{
if (index < 0 || index > 13) throw new ArgumentOutOfRangeException("index");
string propertyName = "Value" + index;
return (double?)GetType().GetProperty(propertyName).GetValue(this);
}
set
{
if (index < 0 || index > 13) throw new ArgumentOutOfRangeException("index");
string propertyName = "Value" + index;
GetType().GetProperty(propertyName).SetValue(this, value);
// Raise your event here
}
}

GWT SelectionModel is returning old selection

I have a cell table with an async data provider. If I update the data via the data provider the table renders the new data correctly but the selection model still holds onto and returns old objects.
Any ideas how to refresh the selection model?
I think you should make your SelectionModel work with different instance of the same "logical" object using the appropriate ProvidesKey. For instance, you could use ProvidesKey that calls getId on the object, so that two objects with the same such ID would be considered equal; so even if the SelectionModel holds onto the old object, it can still answer "yes, it's selected" when you give it the new object.
FYI, this is exactly what the EntityProxyKeyProvider does (using the stableId of the proxy). And the SimpleKeyProvider, used by default when you don't specify one, uses the object itself as its key.
I came across the same issue. Currently I have this as single selection model.
SelectedRow = store it when you select it.
Then when data is reloaded you can clear it by
celltable.getSelectionModel().setSelected(SelectedRow, false);
I guess it is too late for you but hope it helps someone else.
Here is my manual method for refreshing the SelectionModel. This allows you to use the selectedSet() when needed and it will actually contain the current data, rather than the old data - including the removal of deleted rows and updated fields!
I have included bits & pieces of a class extending DataGrid. This should have all the logic at least to solve your problems.
When a row is selected, call saveSelectionKeys().
When the grid data is altered call refeshSelectedSet().
If you know the key type, you can replace the isSameKey() method with something easier to deal with. This class uses generics, so this method attempts to figure out the object conversion itself.
.
public abstract class AsyncDataGrid<T> extends DataGrid<T> {
...
private MultiSelectionModel<T> selectionModel_;
private ListDataProvider<T> dataProvider_;
private List<T> dataList_;
private Set<Object> priorSelectionKeySet_;
private boolean canCompareKeys_;
...
public AsyncDataGrid( final ProvidesKey<T> keyProvider ){
super( keyProvider );
...
dataProvider_ = new ListDataProvider<T>();
dataList_ = dataProvider_.getList();
canCompareKeys_ = true;
...
}
private void saveSelectionKeys(){
priorSelectionKeySet_ = new HashSet<Object>();
Set<T> selectedSet = selectionModel_.getSelectedSet();
for( Iterator<T> it = selectedSet.iterator(); it.hasNext(); ) {
priorSelectionKeySet_.add( super.getValueKey( it.next() ) );
}
}
private void refeshSelectedSet(){
selectionModel_.clear();
if( priorSelectionKeySet_ != null ){
if( !canCompareKeys_ ) return;
for( Iterator<Object> keyIt = priorSelectionKeySet_.iterator(); keyIt.hasNext(); ) {
Object priorKey = keyIt.next();
for( Iterator<T> it = dataList_.iterator(); it.hasNext(); ) {
T row = it.next();
Object rowKey = super.getValueKey( row );
if( isSameKey( rowKey, priorKey ) ) selectionModel_.setSelected( row, true );
}
}
}
}
private boolean isSameRowKey( final T row1, final T row2 ) {
if( (row1 == null) || (row2 == null) ) return false;
Object key1 = super.getValueKey( row1 );
Object key2 = super.getValueKey( row2 );
return isSameKey( key1, key2 );
}
private boolean isSameKey( final Object key1, final Object key2 ){
if( (key1 == null) || (key1 == null) ) return false;
if( key1 instanceof Integer ){
return ( ((Integer) key1) - ((Integer) key2) == 0 );
}
else if( key1 instanceof Long ){
return ( ((Long) key1) - ((Long) key2) == 0 );
}
else if( key1 instanceof String ){
return ( ((String) key1).equals( ((String) key2) ) );
}
canCompareKeys_ = false;
return false;
}
}
I fixed my particular issue by using the following code to return the visible selection. It uses the selection model to determine what is selected and combines this with what is visible. The objects themselves are returned from the CellTable data which is always upto date if the data has ever been changed via an async provider (the selection model data maybe stale but the keys will be correct)
public Set<T> getVisibleSelection() {
/*
* 1) the selection model contains selection that can span multiple pages -
* we want to return just the visible selection
* 2) return the object from the cellTable and NOT the selection - the
* selection may have old, stale, objects if the data has been updated
* since the selection was made
*/
Set<Object> selectedSet = getKeys(selectionModel.getSelectedSet());
List<T> visibleSet = cellTable.getVisibleItems();
Set<T> visibleSelectionSet = new HashSet<T>();
for (T visible : visibleSet) {
if (selectedSet.contains(KEY_PROVIDER.getKey(visible))) {
visibleSelectionSet.add(visible);
}
}
return visibleSelectionSet;
}
public static Set<Object> getKeys(Collection<T> objects) {
Set<Object> ids = new HashSet<Object>();
for (T object : objects) {
ids.add(KEY_PROVIDER.getKey(object));
}
return ids;
}

How to apply like search on GWT cell table?

I am using GWT 2.3.I which I am using GWT cell table.
Here below is the code for my cell table:
public class FormGrid extends SuperGrid {
List<Form> formList;
#Override
public void setColumns(CellTable table) {
TextColumn<Form> nameColumn = new TextColumn<Form>() {
#Override
public String getValue(Form object) {
return object.getName();
}
};
table.addColumn(nameColumn, "Name");
}
#Override
public void setData() {
if (formList != null && formList.size() > 0) {
AsyncDataProvider<Form> provider = new AsyncDataProvider<Form>() {
#Override
protected void onRangeChanged(HasData<Form> display) {
int start = display.getVisibleRange().getStart();
int end = start + display.getVisibleRange().getLength();
end = end >= formList.size() ? formList.size() : end;
List<Form> sub = formList.subList(start, end);
updateRowData(start, sub);
}
};
provider.addDataDisplay(getTable());
provider.updateRowCount(formList.size(), true);
}
}
public List<Form> getFormList() {
return formList;
}
public void setFormList(List<Form> formList) {
this.formList = formList;
}
}
In this my set column and set data will be called fro super class flow.This cell table is working fine.
Now I want to put a filter type facility (like search) in this cell table.It should be like, there is a texbox above the cell table and what ever written in that text box, it should fire a like query to all form name for that text box value.
for example I have 1000 form in the grid.Now if user writes 'app' in some filter textbox above the cell table the all the form which have 'app' in there name will be filtered and grid has only those forms only.
This is the first case:
Another case is I am only render one column in grid name.I have two more properties in form (description,tag).But I am not rendering them.now for filter if user writes 'app' in filter box then it should make a query to all three (name, description, and tag) and should return if 'app' matched to any of three.
I am not getting how to apply filter in cell table.
Please help me out.Thanks in advance.
You can find an implementation in the expenses sample.
Here is a short summary of the steps
1.) Create a Textbox and a SearchButton.
2.) add a clickHandler to the SearchButton (You can also add KeyUpHandler to the Textbox alternatively)
searchButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
search();
}
});
3.) In the search function retrieve the searchString and store it.
private void search() {
searchString = searchBox.getText();
setData();
}
4.) modify your setdata() function to take searchString into account
#Override
public void setData() {
if (formList != null && formList.size() > 0) {
AsyncDataProvider<Form> provider = new AsyncDataProvider<Form>() {
#Override
protected void onRangeChanged(HasData<Form> display) {
int start = display.getVisibleRange().getStart();
int end = start + display.getVisibleRange().getLength();
//new function if searchString is specified take into account
List<Form> sub = getSubList(start,end);
end = end >= sub.size() ? sub.size() : end;
updateRowData(sub.subList(start, end);, sub);
}
};
provider.addDataDisplay(getTable());
provider.updateRowCount(formList.size(), true);
}
}
private List<Form> getSubList(int start, int end) {
List<Form> filtered_list = null;
if (searchString != null) {
filtered_list= new ArrayList<Form>();
for (Form form : formList) {
if (form.getName().equals(searchString) || form.getTag().equals(searchString) || form.getDescription().equals(searchString))
filtered_list.add(form);
}
}
else
filtered_list = formList;
return filtered_list;
}
can propose another solution what can be used quite easy multiple times.
Idea is to create custom provider for your celltable.
GWT celltable filtering
Video in this post shows it in action.
Here is the part of code of custom list data provider which u have to implement.
#Override
protected void updateRowData(HasData display, int start, List values) {
if (!hasFilter() || filter == null) { // we don't need to filter, so call base class
super.updateRowData(display, start, values);
} else {
int end = start + values.size();
Range range = display.getVisibleRange();
int curStart = range.getStart();
int curLength = range.getLength();
int curEnd = curStart + curLength;
if (start == curStart || (curStart < end && curEnd > start)) {
int realStart = curStart < start ? start : curStart;
int realEnd = curEnd > end ? end : curEnd;
int realLength = realEnd - realStart;
List<t> resulted = new ArrayList<t>(realLength);
for (int i = realStart - start; i < realStart - start + realLength; i++) {
if (filter.isValid((T) values.get(i), getFilter())) {
resulted.add((T) values.get(i));
}
}
display.setRowData(realStart, resulted);
display.setRowCount(resulted.size());
}
}
}

Specifying which Cell should receive focus next in a CellTable

I'm using GWT 2.1.0
I have a CellTable populated with Columns that use different Cells to edit different types of values (e.g. date, string, etc). I want the user to be able to click in a cell, type a value, and hit enter to go directly to editing the next cell down, or tab to go directly to editing the next cell over.
I've been looking through the Cell and CellTable interfaces but can't find anything that looks relevant. How can I achieve this effect?
I had a similar requirement and I could not find a out-of-the-box solution. I ended up subclassing TextInputCell and add tabIndex support myself.
Here's some bits and pieces of the subclass (hopefully it will compile, too lazy to check). Unfortunately I cannot post the entire subclass, since it has lot may other things which are not related to the current question. This solution takes care of tabbing to the next cell, but for enter support, you may need to override onBrowserEvent.
public class EditTextInputCell extends TextInputCell
{
int startTabIndex;
interface TabbedTemplate extends SafeHtmlTemplates
{
#Template( "<input type=\"text\" value=\"{0}\" tabindex=\"{1}\" class=\"{2}\" title=\"{3}\"></input>" )
SafeHtml input( String value, String tabindex, String styleClass, String title );
}
private static TabbedTemplate template;
public EditTextInputCell( int startTabIndex )
{
this.startTabIndex = startTabIndex;
}
#Override
public boolean isEditing( Context context, Element parent, String value )
{
return true;
}
#Override
public void render( Context context, String value, SafeHtmlBuilder sb )
{
// Get the view data.
Object key = context.getKey( );
ValidationData viewData = getViewData( key );
if ( viewData != null && value.equals( viewData.getCurrentValue( ) ) )
{
clearViewData( key );
viewData = null;
}
String strToDisp = ( viewData != null && viewData.getCurrentValue( ) != null ) ? viewData.getCurrentValue( ) : value;
String tabIndex = "" + startTabIndex + context.getIndex( ) + context.getColumn( );
boolean invalid = ( viewData == null ) ? false : viewData.isInvalid( );
String styleClass = "cellTableCell-valid";
String errorMessage = "";
if ( invalid )
{
styleClass = "cellTableCell-invalid";
errorMessage = viewData.getMessage( );
}
if ( strToDisp != null )
{
SafeHtml html = SimpleSafeHtmlRenderer.getInstance( ).render( strToDisp );
// Note: template will not treat SafeHtml specially
sb.append( getTemplate( ).input( html.asString( ), tabIndex, styleClass, errorMessage ) );
}
else
{
sb.appendHtmlConstant( "<input type=\"text\" tabindex=\"" + tabIndex + "\" class=\"" + styleClass + "\" title=\"" + errorMessage + "\"></input>" );
}
}
private TabbedTemplate getTemplate( )
{
if ( template == null )
{
template = GWT.create( TabbedTemplate.class );
}
return template;
}}