I'm using a DatePicker (org.apache.wicket.extensions.yui.calendar.DatePicker — Javadoc) in a form. The form consists of two fields. The first field is a dropdown, and the second changes dynamically based on the first. If "text" is selected, a textbox comes up; if "list" is selected, a dropdown menu comes up; and if "date" is selected, a date picker and associated field come up.
Here's a simplified version of my current code:
DateTextField dateField = new DateTextField("dateField", // ...
DatePicker datePicker = new DatePicker();
dateField.add(datePicker);
fieldOne.add(new OnChangeAjaxBehavior() {
protected void onUpdate(AjaxRequestTarget target) {
if (fieldOne.equalsIgnoreCase("list"))
{
dateField.setVisible(false);
// datePicker.setVisible(false); // This line is impossible
listField.setVisible(true);
textField.setVisible(false);
}
else if { /* similar visibility settings for dates and text */ }
}
});
The form currently works properly for changing to the date picker. The problem arises when date is selected and then the user selects something else. The date field disappears, but the date picker remains on the screen. Unfortunately, it doesn't seem to have a setVisible() method, or any equivalent. In fact, it's not even a true Wicket Component.
How can I make them appear/disappear together? If I can't set the picker's visibility directly, can I tie it to the field's visibility somehow?
By far the easiest yet still fairly maintainable solution is to group the components you want to hide together in a WebMarkupContainer. In the markup you'll probably want to use a <div> element for the container, but this depends on what you want to hide. (Sometimes the markup itself prevents you from using this method but let's hope your markup doesn't. :))
Then just change the visibility of the container.
A good idea with AjaxListeners also is to call .setOutputMarkupId(true) on the Component you want to handle. Otherwise you are possibly not able to "locate" it.
In case you are not rendering it on load, but intend to add the component later, I think you should also call setOutputMarkupPlaceholderTag(true).
This helped me several times...
Related
I have a form that contains a text field input that is bound to a field in a model object. When a user enters data into that text field it can affect multiple other fields/components within the form based on calculations. My business logic is encapsulated in a service layer.
Theoretically the way I want this to work is that when the user updates the field, an ajax call is made to the server (on keypress) where the logic from the service is applied and all affected fields are updated on the model object. Once the model has been updated on the server, I want to sync the current state of the model object to the screen.
Is the only way to do this to refresh the entire screen? Is there a way to re-render only the components bound to the fields in the model that have changed? Also, if I refresh the screen, the field that is being edited is updated as well, is there a way to exclude this?
I am interested in any best practices for this technique.
Thanks
I assume from your tags that you're using wicket. Wicket uses Behaviors for this purpose. In the following example you will update both DropDownChoices if the input of the TextField changed. You just need to add those controls to the AjaxRequestTarget. Models of both DropDownChoices will be reloaded and rerendered at the frontend. Also make sure to call setOutputMarkupId(true) on controls you want to update.
TextField<String> textField = new TextField<String>("input");
Component dropDownA = new DropDownChoice<>("dropA").setOutputMarkupId(true);
Component dropDownB = new DropDownChoice<>("dropB").setOutputMarkupId(true);
textField.add(new AjaxFormComponentUpdatingBehavior("change") {
private static final long serialVersionUID = 1478280524536023725L;
#Override
protected void onUpdate(AjaxRequestTarget target) {
target.add(dropDownA);
target.add(dropDownB);
}
});
With Ajax you can update any Component you want, just make sure it has markup id (Component.setOutputMarkupId(true)).
You need to use AjaxFormComponentUpdatingBehavior or AjaxFormChoiceComponentUpdatingBehavior and in its onUpdate() callback you have to update the models of the respective FormComponents and then you can use FormComponent.this.getForm().visitChildren(FormComponent.class, IVisit) to visit all FormComponents of the current Form and add to AjaxRequestTarget only the ones you have updated.
Update
Another good solution (even better!) is to use Wicket Event bus. In the Ajax behavior you could broadcast an event:
component.send(getForm(), Broadcast.BREADTH, new UIChangedEvent(target, newValue));
where UIChangedEvent is your own class/POJO that brings the new value of the updated component and the AjaxRequestTarget.
Then the other FormComponents could override #onEvent() and use the value to calculate their new value and use the target to update themselves or not, depending on the earlier calculation.
I am currently trying to setEditable for a DatePicker to false so the value cannot be changed. Using the following only disables the text field, but still allows the changing of the date by clicking on the calendar button (the setEditable is for permissions, so I can enable/disable depending on the login):
exampleDatePicker.setEditable(user.getGroup().equals(admin));
Is there a way to disable the Calendar button on the DatePicker? I don't want to use setDisable, as I still want the field to be readable, and I can't change the CSS for disabled because I have other DatePickers that get disabled that I want greyed out.
For future searches, here's what I did:
dtpDate.setDisable(true);
dtpDate.setStyle("-fx-opacity: 1");
dtpDate.getEditor().setStyle("-fx-opacity: 1");
To disable it (i.e make it behave like it's disabled), call setDisable(...):
exampleDatePicker.setDisable(! user.getGroup().equals(admin));
To change the appearance from the default disabled look (which I agree is very hard to read), you can still use CSS, but choose this DatePicker specifically. The easiest way is probably to use a CSS pseudoclass:
PseudoClass notAuthenticated = PseudoClass.getPseudoClass("not-authenticated");
exampleDatePicker.setDisable(! user.getGroup().equals(admin));
exampleDatePicker.pseudoClassStateChanged(notAuthenticated, ! user.getGroup().equals(admin));
and then in your external CSS you can set styles for .date-picker:not-authenticated, e.g.:
.date-picker:not-authenticated, .date-picker:not-authenticated > .text-field {
-fx-opacity: 0.85 ;
}
I would recommend making the date picker look a little different from a truly active (not disabled) date picker, or else it may be confusing to the user.
Better way to do it:
yourDatepicker.setOnMouseClicked(e -> {
if(yourDatepicker.isDisabled && yourDatepicker.isShowing())
yourDatepicker.hide();
});
This way when you click on it, the popup won't show ;)
Cheers
datePicker.setEditable(false);
datePicker.setOnMouseClicked(e -> {
if(!datePicker.isEditable())
datePicker.hide();
});
I was confused in this issue. Finally I found that elegant way to resolve:
yourDatepicker.getEditor().setDisable(true);
Well, just get editor of your datepicker and disable it!
I need to build a View which has a 4 layer nested Multi-Accordion with a lot of checkboxes inside them. All together there might be around 30-40 Checkboxes all through the Accordions.
The next step will be, that i have some sort of logic behind all this. Depending on the selection combination of the checkboxes I will change a text label accordingly.
My thought process was: I put up all these checkboxes and give them a numeric fx:id representing there position in the nested accordion graph. Something like "1_1" or "2_4_1".
After that, I build one ChangeListener calling a Method on Selection of a Checkbox. I can look up the Id of the checked box, look it up in my data (to see which Text belongs to it and if any rules interfer with other boxes) and handle the logic accordingly while putting the id and its text in a Map or List to keep it for later and to keep track of the checked boxes.
Now I came to know, that getting the fx:id isnt something JavaFX wants me to do. I cant deliver a custom id in custom property inside the FXML either (couldnt find anything regarding this).
I am now pretty much at the end of my knowledge (I did just start with JavaFX and have some basic Java knowledge) and it seems to me, that I tackle this topic from the wrong side.
My question is now: What would be a best practice to handle dozens of checkboxes and trigger logic in the code according to the box that was checked without writing a ChangeListener for every single Check Box leaving me with some (imo) ugly code all the way.
EDIT: I forgot to mention: I did achieve some sort of functional solution by writing a custom CheckboxChangeListener with a reference to the Element the addListener method was called on and using "getId()" on this reference. I came to know though, that this method references the css:id of the fxml element and not its fx:id and I am not quite sure if this is a proper way to go
You should look into databinding with javafx. For example:
CheckBox cb1 = new CheckBox("1");
CheckBox cb2 = new CheckBox("2");
BooleanProperty isCb1Selected = cb1.selectedProperty();
BooleanProperty isCb2Selected = cb2.selectedProperty();
Textfield foo = new TextField().visibleProperty().bind(isCb1Selected.and(isCb2Selected));
This would hide the textfield foo if atleast one of the checkboxes isn't selected.
You can find other examples here and here an oracle tutorial
I have two JDateChoosers, One with label 'Start Date' & another with 'End Date'.I have two radio buttons 'single Day' & 'Multiple Day'.If I select 'Single Day' I want to display same date to 'End Date' which selected in 'Start Date'. And I also want to clear these JDateChooser fileds on CLEAR_BUTTON_CLICK.How do I write this? I am using this control first time..
Plz,help me..
Thanks in advance..
I'm assuming that you are talking about JDateChooser from JCalendar. Am I correct? The JDateChooser fires a PropertyChangeEvent when its date is changed. So, to set the date of another JDateChooser, you need to add an event handler to the "source" component to deal with the change event. When it is fired, you take the date of the component using getDate() method and set it to the target component, using setDate() method. As you are using a component suite that I don't have installed here, it is difficult to implement a correct solution to you.
Take a look in the docs: http://www.toedter.com/en/jcalendar/api/com/toedter/calendar/JDateChooser.html
I think that reading this you will be able to do what you want.
Edit: Here is some code. Try to use it. I really don't have certain that it will works since I didn't test it.
// sourceDateChooser and targetDateChooser MUST be final,
// since they will be accessed inside a anonymous inner class
sourceDateChooser.addPropertyChangeListener( new PropertyChangeListener(){
#Override
public void propertyChange(PropertyChangeEvent evt) {
// the docs of JDateChooser says that when the date is modified, a "date" property change is fired
if ( evt.getPropertyName().equals( "date" ) ) {
targetDateChooser.setDate( sourceDateChooser.getDate() );
}
}
});
I've subclassed Swingx's ComponentProvider to provide JButtons but on some lines of my JXTreeTable, I don't want to show any button. The final "result" I want is to have an empty cell, like what I get when showing an empty text in a column for which I haven't set a provider.
Is it possible to hide the rendered component on certain rows (depending on the value for example)? Setting setVisible(false) on the rendered component in format() or configureState() doesn't work.
Is it possible to subclass ComponentProvider to provide different several types of Components? If yes, how would that work?
Where can I find some examples of the possibilities that the ComponentProvider offers and a clear explanation of which method does what (for example, I hardly understand the difference between configureState() and format())?
EDIT
Is it possible to prevent a JButton displayed in a JX(Tree)?Table to be as wide as the cell?
If I create another highlighter, can I use another predicate (ROLLOVER or something) to change the cursor? The cursor change to a hand (over a link) even if the button is hidden.
Many thanks!
Interesting :-)
generally doesn't work because the CellRendererPane doesn't respect the component's visible property - it stamps it always. BUT: can work in SwingX if the actual provider it wrapped into a WrappingProvider and then that wrapper's component is set invisible.
a snippet, just as proof-of-concept
table.getColumn(1).setCellRenderer(new DefaultTableRenderer(
new WrappingProvider(IconValues.NONE, new ButtonProvider(), false) {
#Override
protected void configureState(CellContext context) {
super.configureState(context);
rendererComponent.getComponent().setVisible(context.getRow() != 5);
}
}
));
On the other hand, the provider is not the place for plugging in custom context-dependent configuration. That should be done in a Highlighter, as f.i. in
AbstractHighlighter highlighter = new AbstractHighlighter(HighlightPredicate.EVEN) {
#Override
protected Component doHighlight(Component component,
ComponentAdapter adapter) {
((WrappingIconPanel) component).getComponent().setVisible(false);
return component;
}
#Override
protected boolean canHighlight(Component component,
ComponentAdapter adapter) {
return component instanceof WrappingIconPanel;
}
};
table.addHighlighter(highlighter);
Which doesn't work as expected (the button is always hidden) because is not one of the properties which are guaranteed to be reset in the provider. Nothing prevents custom providers to extend those guarantees, like
table.getColumn(1).setCellRenderer(new DefaultTableRenderer(
// custom wrappingProvider which guarantees the reset of visible
// property of the wrapped component
new WrappingProvider(IconValues.NONE, new ButtonProvider(), false) {
#Override
protected void configureState(CellContext context) {
super.configureState(context);
rendererComponent.getComponent().setVisible(true);
}
}
));
Now the highlighter can fearlessly change the visible based on context. A slight visual glitch: the WrappingIconPanel always leaves some space for the icon, even if there is none - not quite sure why that happens or whether it would be safe (in SwingX) to remove that spacing (the wrappingProvider originally is meant for use in JXTree, it's not installed by default because there are still issues with ComponentOrientation).
(2 in the question) not supported, the componentProvider is designed to return the same single component configured with the exact same properties on each call
(3 in the question) cough ... no, nothing but the sources and examples (in the demos and the test packages)
Edit (to answer the edited part of the question)
no, with the current WrappingIconpPanel: it does use a Borderlayout which - as we all know :-) doesn't respect max size. Using a BoxLayout would but had issues that I don't fully remember. Nevertheless, that would be the place to tweak, so that the button's max would be respected
hmmm ... not entirely sure how you implemented the cursor change. Assuming that it's in your ButtonProvider: implement the isRolloverEnabled to return true/false depending on whether it is visible or not Edit-in-Edit doesn't work. Don't know why, could be that this is a bug in rollover-dectection and/or handling in WrappingProvider
Off into the weekend now :-)