Is there a way to have the DropDownChoice in Wicket assign tooltips (e.g. title attributes) to individual option elements?
I have selectbox items in the following form:
public class SelectBoxItem
{
private Long id;
private String label;
private String description;
}
All items are loaded from the database.
I configure the DropDownChoice component using a ChoiceRenderer to use the ids as keys and the labels as values.
Now I would need to configure it to use the descriptions as tooltip messages as well.
I have only found this related thread on the Internet. Browsing the relevant Wicket classes let me to the same conclusions as the author, e.g. that this was probably not possible with the current versions of the DropDownChoice/ChoiceRenderer classes. Is that right? And in that case, is there a similar component which would allow that?
(For a more comprehensive description of my code base see my other question where I asked about a different problem within the same context.)
Here is my solution for this problem. Many thanks to Andrea Del Bene for the advice.
public class TitledDropDownChoice<T> extends DropDownChoice<T> {
// ... constructors from superclass ...
#Override
protected void appendOptionHtml(AppendingStringBuffer buffer,
T choice, int index, String selected) {
super.appendOptionHtml(buffer, choice, index, selected);
// converts <option value="foo">bar</option> to
// <option value="foo" title="bar">bar</option>
String replString = "value=\"" + getChoiceRenderer()
.getIdValue(choice, index) + "\"";
int pos = buffer.indexOf(replString);
buffer.insert(pos + replString.length(),
" title=\"" + getChoiceRenderer().getDisplayValue(choice) + "\"");
}
}
Have you tried overriding method appendOptionHtml? You could use it to append the desired html (i.e. title="toolTipText").
Related
I'm currently working on a CRUD application and I have defined a LOV like this:
My question is how can I get all these return values in for example a ValueChangeListener defined like this:
public void onValueChanged(ValueChangeEvent ev){
BindingContext bctx = BindingContext.getCurrent();
oracle.binding.BindingContainer bindings = bctx.getCurrentBindingsEntry();
DCIteratorBinding iterBind = (DCIteratorBinding)bindings.get("MpStavkeulazaView5Iterator");
System.out.println("Vrijednost je" + ev.getNewValue());
}
This code only gives me the value of the list attribute, but I want the other values too.
Any other info please tell me.
First of all - using backing bean's value change listener is not ideal for such use case:
Try instead the setter on your Row Impl for the same purpose.
Remember: if you can't test your use case from BC tester, your ADF design is flawed.
Second of all: your LOV can return multiple values:
http://adfbugs.blogspot.co.uk/2009/11/returning-multiple-values-from-lov-in.html
You can bind row attributes and then get values of this bindings or just get this attributes from iterator. If you going to handle it in valueChangeListener you'll have to process updates, before getting this values:
public void onValueChanged(ValueChangeEvent ev){
BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
DCIteratorBinding iterBind = (DCIteratorBinding)bindings.get("MpStavkeulazaView5Iterator");
System.out.println("Vrijednost je" + ev.getNewValue());
ev.processUpdates(FacesContext.getCurrentInstance());
Row row = iterBind.getCurrentRow();
System.out.println("Proizvod: " + row.getAttribute("Proizvod"));
System.out.println("Jmjere: " + row.getAttribute("Jmjere"));
}
However its may be better to use Transient attribute in your ViewObject and do calculations there?
In Wicket there are 2 versions of an AutoCompleteTextField, one in wicket-extensions and the other in com.googlecode.wicket. I am trying to use one of them in a Wicket ModalWindow, but I am having problems with both.
Both versions are generally OK on a webpage without using modal windows but I need them inside of one. There is some limited examples out there but nothing specific to modal dialogs.
Wicket Extension version:
Using Wicket 6.11.0
final AutoCompleteTextField<T> field = new AutoCompleteTextField<T>( "component", getSelectionModel(), theclass, new AutoCompleteSettings() ) {
private static final long serialVersionUID = 1L;
#Override
protected Iterator<T> getChoices( String input ) {
return AutoCompleteSelect.this.getChoices( input ).iterator();
}
};
field.setOutputMarkupPlaceholderTag( true );
field.add( new AjaxFormComponentUpdatingBehavior( "change" ) {
private static final long serialVersionUID = 1L;
#Override
protected void onUpdate( AjaxRequestTarget target ) {
System.out.println( "Item selected! " + getSelectionModel().getObject() );
// This is never called!
}
} );
add( field );
Originally I was having problems getting this to work at all until I realized that it doesn't fetch the choices until you press the down key. If I put one in a ModalWindow, it's popup location gets screwed up and the suggestions appear off to the bottom right of the screen. Moving the dialog to the lower right of the screen accentuates the problem.
Questions:
How do you get the popup to appear as someone types into the text field, rather than when they hit the down key?
What is the best way to get an ajax onSelected-style call (like the one in the google version?) There is a version in the wicket examples [1] that relies on a form submission but this is no good if you need it before that.
Google Version:
Using com.googlecode.wicket-jquery-ui version 6.11.0
ITextRenderer<T> renderer = new ITextRenderer<T>() {
private static final long serialVersionUID = 1L;
#Override
public String getText( T object ) {
return object == null ? "" : object.toString();
}
#Override
public String getText( T object, String expression ) {
return object == null ? "" : expression + "." + object.toString();
}
};
final AutoCompleteTextField<T> field = new AutoCompleteTextField<T>( "component", getSelectionModel(), renderer, m_class ) {
private static final long serialVersionUID = 1L;
protected void onSelected( AjaxRequestTarget target ) {
System.out.println( "Item " + getSelectionModel().getObject() + " has been selected" );
}
#Override
protected List<T> getChoices( String input ) {
return AutoCompleteSelect.this.getChoices( input );
}
};
Though this initially works better (onSelected is useful and the popup appears in the correct place) putting it in a modal dialog makes the popup appear underneath the dialog. This can be fixed by changing the z-index through CSS (a bit messy but works), but there seems to be an event fired that hides the popup whenever you hover over it meaning nothing can be selected.
Has anyone managed to stop the popup from disappearing?
Is there a better way to deal with the z-index issue?
Wicket Extension Examples: http://www.wicket-library.com/wicket-examples/ajax/autocomplete?0
Google examples: http://www.7thweb.net/wicket-jquery-ui/autocomplete/ConverterAutoCompletePage?0
Thanks in advance.
Update to the latest Wicket 6.19.0 and see if the problems go away. Since 6.11.0 there were a few bugs regarding autocomplete fields and modal windows resolved:
https://issues.apache.org/jira/browse/WICKET-4294
https://issues.apache.org/jira/browse/WICKET-5378
https://issues.apache.org/jira/browse/WICKET-5609
https://issues.apache.org/jira/browse/WICKET-5379
https://issues.apache.org/jira/browse/WICKET-5413
Maybe they will solve your problems without the need of any hacking.
For the Wicket jQuery UI one, this is by design and this should be handled by the user directly
https://groups.google.com/forum/#!searchin/wicket-jquery-ui/autocomplete/wicket-jquery-ui/bwSVY4mlrac/q-dRK1EUr6cJ
<wicket:head>
<style type="text/css">
.ui-autocomplete {
z-index: 9999 !important;
}
</style>
</wicket:head>
If this does not solve your issue, feel free to attach a quickstart that demonstrates the problem in the dedicated forum...
Best regards,
Sebastien
I have an object with two essential fields that must be displayed for the user together in ComboBox something kind of:
MyObject {
Long id;
Integer from;
Integer to;
...
}
My properties look like :
MyObjectProperties {
ModelKeyProvider<MyObject> id();
LabelProvider<MyObject> from();
LabelProvider<MyObject> to();
...
}
I'm trying to display **from - to** in each combobox cell, is it possible using GXT 3 ComboBox?
That's not working for me because i can't use LabelProvider for an int and can't merge two wroperties in same field!
LabelProvider is in fact the only clean way to go, but you need only one LabelProvider:
LabelProvider<MyObject> labelProvider = new LabelProvider<MyObject>(){
#Override
public String getLabel(MyObject item){
return item.getFrom() + " - " + item.getTo();
}
}
And assign it at ComboBox creation time:
ComboBox<MyObject> cb = new ComboBox<MyObject>(store, labelProvider);
This is my zul code:
<combobox id="digitalPublisherCombobox" value="#load(ivm.inventory.digitalPublisherName)"
onOK="#command('setDigitalPublisher', digitalPublisherBox = self)"
onSelect="#command('setDigitalPublisher', digitalPublisherBox = self)"
onChanging="#command('setupQuicksearchByEvent', searchlayout = event, prefix = 'PUB', tags = 'PublisherName, PublisherNameTranslit')"
mold="rounded" hflex="1" buttonVisible="false" autodrop="true">
<comboitem self="#{each=entry}" value="#{entry.key}" label="#{entry.value}"/>
</combobox>
And this is QuickSearch implementations:
#Command
public void setupQuicksearchByEvent(#BindingParam("searchlayout")Event event, #BindingParam("prefix") String prefix, #BindingParam("tags") String tags) throws WrongValueException, SearchException, IOException
{
if(event instanceof InputEvent)
{
InputEvent inputEvent = (InputEvent) event;
String inputText = inputEvent.getValue();
List<String> searchFields = Arrays.asList(tags.split(","));
ListModel model = new ListModelMap(ZKLogic.findDocsStartingWith(prefix, searchFields, "proxy", inputText), true);
ListModel subModel = ListModels.toListSubModel(model, Autocompleter.MAP_VALUE_CONTAINS_COMPARATOR, 10);
Combobox searchBox = (Combobox) event.getTarget();
searchBox.setModel(subModel);
searchBox.setItemRenderer(new ComboitemRenderer()
{
#Override
public void render( Comboitem item, Object data, int pos ) throws Exception
{
String publisherString = data.toString();
UID key = getUidFromPublisherString(publisherString);
int startIndex = publisherString.indexOf('=') + 1;
String publisher = publisherString.substring(startIndex);
item.setLabel(publisher);
item.setValue(key);
}
});
}
}
ZKLogic.findDocsStartingWith return map with UID-key and String-value.
With code above I achieved to get dropdown list when I switch to another window. I need to type something, then select another browser or notepad window - and comboitems will be displayed immediately.
So, my question still need answer, is there are any techniques to reproduce this windows switching in code? Or maybe I should do something with autocomplete, because I've got some ac working with preloaded lists, but this thing should return only 10 records from db, instead of all 70000 entries, every time when user type something in the field.
Edit 20/09/2013: Problem still exist. Rename question a bit, because thing that I need is to call render option by force in code. Is there is any way to do it? Code hasn't changed a lot, but print option in render method said, that method can miss two or more onChange events and suddenly render text for one variant.
Maybe you know another autocomplete options in zk framework where database participating? I'm ready to change implementation, if there is a guide with working implementation of it.
Ok I see two problems, you should solve first.
Setting the Renderer in every call of setupQuicksearchByEvent(...).
that is not logical, cos it is the same every time.
Add to the zul combobox tag something like
itemRenderer="#load(ivm.myRenderer)" ....
If you want just 10 items, do not let the db-request return more then 10.
If you use JPA klick here or for sql here or just google a bit.
After you fixed this two issues, we can exclude these as a reason of the unexpected behavior and fix it, if it is still present.
Edit
Ok, I have two possible ways to fix it.
Call Combobox#invalidate()
This schould force zk to rerender the Combobox, but could
lead to low performance and I would not prefer this.
Use Listbox with the select mold instead of Combobox.
To force the rerender, use Listbox#renderAll()
Try setting the selected item on your combobox or throw its related event
Solution is simple. Really. Nothing is better then brute-force, but I think I tried to avoid it and use it in despair.
#Command
public void setupQuicksearchByEvent(#BindingParam("searchlayout")Event event, #BindingParam("prefix") String prefix, #BindingParam("tags") String tags) throws WrongValueException, SearchException, IOException
{
if(event instanceof InputEvent)
{
InputEvent inputEvent = (InputEvent) event;
String inputText = inputEvent.getValue();
List<String> searchFields = Arrays.asList(tags.split(","));
Map<UID, String> publishers = ZKLogic.findDocsStartingWith(prefix, searchFields, "proxy", inputText);
Combobox searchBox = (Combobox) event.getTarget();
searchBox.getChildren().clear();
for (Map.Entry<UID, String > entry : publishers.entrySet())
{
Comboitem item = new Comboitem();
item.setLabel(entry.getValue());
item.setValue(entry.getKey());
searchBox.appendChild(item);
}
}
}
I am facing a problem regarding readability and cross-platform issues.
We are generating our UI on the fly, using certain classes and subclasses. For an example, I will use basic elements (not UI ones), but I think the "problem" should be obvious.
I am asking IF there is any configuration switch in Simple (http://simple.sourceforge.net/home.php) to achieve the desired result. As said, its about readability for another platform, if I would only have to target JAVA, I would not care about the look and feel of the XML.
So, in my example, I serialize a simple class, the result is:
<GuiElementExamples>
<LastCreated>2012-04-15 16:48:59.813 CEST</LastCreated>
<NonGuiObject>
<objectBase class="objects.single.simple.StringObject" _value="">
<_readonly>false</_readonly>
</objectBase>
<objectBase class="objects.single.simple.StringProperty">
<_items>
<object class="objects.single.simple.StringObject" _value="Label">
<_readonly>true</_readonly>
</object>
<object class="objects.single.simple.StringObject" _value="">
<_readonly>false</_readonly>
</object>
</_items>
<_readonly>false</_readonly>
</objectBase>
</NonGuiObject>
</GuiElementExamples>
What I would love to have (I will create it by hand as an example), is this:
<GuiElementExamples>
<LastCreated>2012-04-15 16:48:59.813 CEST</LastCreated>
<NonGuiObject>
<StringObject _value="">
<_readonly>false</_readonly>
</StringObject>
<StringProperty>
<_items>
<StringObject _value="Label">
<_readonly>true</_readonly>
</StringObject>
<StringObject _value="">
<_readonly>false</_readonly>
</StringObject>
</_items>
<_readonly>false</_readonly>
</StringProperty>
</NonGuiObject>
</GuiElementExamples>
I KNOW there will be NO clashes in class names, and one option I could use is a simple search and replace script, but maybe there is an option to configure "simple" in a way to export the stuff as shown above.
I am aware that there would be no way to DESERIALIZE stuff in the format above, without running e.g. the mentioned script before, because without the fully qualified class name, simple can't know which object to create..
Thanks for any help or workaround ideas,
Chris
Like always, after writing it, and going back to the docs, I found it :-)
It is the last entry on the tutorial page, in my example this does the trick:
EDIT This does not work with more then one element, dont ask me why EDIT
#ElementListUnion({#ElementList(entry = "StringObject", type = StringObject.class)})
private ArrayList<T> _items = new ArrayList<T>();
The solution I used is a little bit more complicated, but get the job done. I will post the source here to point you in the right direction (ObjectBase is the base class of all my objects I want to "rename" the way described above):
public class FormatVisitor implements Visitor
{
private static ILogger _logger = LogManager.GetLogger(FormatVisitor.class);
#Override
public void read(Type type, NodeMap<InputNode> strings) throws Exception
{
}
public void write(Type type, NodeMap<OutputNode> node)
{
OutputNode element = node.getNode();
Class javaType = type.getType();
if (ObjectBase.class.isAssignableFrom(javaType))
{
_logger.Verbose("Old name was " + element.getName());
element.setName(javaType.getSimpleName());
_logger.Verbose("Changing name to " + javaType.getSimpleName());
}
try
{
String className = element.getAttributes().get("class").getValue();
Class localClass = Class.forName(className);
boolean shouldShortenName = ObjectBase.class.isAssignableFrom(localClass);
if (shouldShortenName)
{
element.getAttributes().remove("class");
element.setName(localClass.getSimpleName());
}
}
catch (Exception e)
{
e.printStackTrace();
}
if (ObjectBase.class.isAssignableFrom(javaType))
{
element.setName(type.getType().getSimpleName());
}
}
}