I have to add a class to a component. I can't add the component via ajax because this is a problem with the input. My code is:
private ListView<Opzioni> setListOpzioni(boolean b) {
return new ListView<Opzioni>("list_opzioni", opzioniDao.findAll()) {
#Override
protected void populateItem(ListItem<Opzioni> item) {
erroriAssociatiAlTextField = new HashMap<>();
List<Opzioni> opzioniCron = opzioniDao.getOpzioniFormatore();
final Opzioni o = item.getModelObject();
final WebMarkupContainer errorContainer = new WebMarkupContainer("errorContainer");
errorContainer.setOutputMarkupId(true);
errorContainer.setOutputMarkupPlaceholderTag(true);
Boolean isSelected = false;
Boolean isAzienda = o.getAzienda() != null ? o.getAzienda().equals(getAziendaLogged()) : false;
if (isAdminFormatore(getUserLogged())) {
isSelected = o.getControlFormatore() || isAzienda;
} else {
isSelected = isAzienda;
}
Boolean visibile = isSa || isSelected;
Label name_op = new Label("name_op", o.getName());
item.add(name_op.setVisible(visibile));
TextField val_op = new TextField("val_op", new PropertyModel(o, "val"));
val_op.add(new OnChangeAjaxBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget art) {
if (opzioniCron.contains(o)) {
controllaStringa(o);
}
if (valoriScorretti == true) {
contatore++;
} else {
contatore = 0;
}
if (contatore > 0) {
ciSonoErrori = true;
String error = "Valori inseriti nel box " + o.getName() + " non corretti";
if (!erroriAssociatiAlTextField.containsKey(o)) {
erroriAssociatiAlTextField.put(o, error);
}
for (Map.Entry<Opzioni, String> map : erroriAssociatiAlTextField.entrySet()) {
val_op.error(map.getValue());
}
art.add(errorContainer.setVisible(true));
refreshFp(art);
art.add(save_btn.setVisible(false));
} else {
ciSonoErrori = false;
if (!erroriAssociatiAlTextField.isEmpty()) {
art.add(save_btn.setVisible(false));
if (erroriAssociatiAlTextField.containsKey(o)) {
erroriAssociatiAlTextField.remove(o);
}
for (Map.Entry<Opzioni, String> map : erroriAssociatiAlTextField.entrySet()) {
val_op.error(map.getValue());
}
}
if (erroriAssociatiAlTextField.isEmpty()) {
art.add(save_btn.setVisible(true));
}
art.add(errorContainer.setVisible(false));
refreshFp(art);
}
}
});
item.add(val_op.setEnabled(b).setVisible(visibile));
item.add(errorContainer.setVisible(false));
if (visibile) {
o.setModificato(true);
} else {
o.setModificato(false);
}
}
};
}
With this code every time a user insert a letter inside the field the cursor go to the first position and it's impossible to use it. Is there an alternative mode to add the class dynamically?
With this code every time a user insert a letter inside the field the
cursor go to the first position and it's impossible to use it.
That is because of the OnChangeAjaxBehavior you are using.
This behavior checks after every user input if the FormComponent validates correct and if it does it will call the onUpdate method.
For a TextField without an IValidator added that means onUpdate is called after every input. If you then reprint the TextField via AjaxRequestTarget you get the behaviour of an input field where you type "backwards" as you currently do.
how can i modify attributes without adding the component in Wicket?
If you want you're changes to be visible in the browser then you need to update the component with ajax at some point. There is no way around it.
You probably have to rethink you're aproach because what you are currently doing doesn't make much sense.
At the moment you have a TextField and when the user enters something that is valid you add the css class "field-error" to the html input.
Shouldn't it be the other way around and the " field-error" should get added when the users enters something that is invalid?
Do you really want to validate and do an ajax update while the user enters something? Why not validate the input when the form/textfield actually gets submitted, or when the user is done typing into the field?
Edit
Instead of updating the input with the AjaxRequestTarget you could use the AjaxRequestTarget to send the jQuery command to add the css class to the input:
val_op.setOutputMarkupId(true);
val_op.add(new OnChangeAjaxBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget art) {
art.appendJavaScript("$('#"+val_op.getMarkupId()+"').addClass('field-error');");
}
}
Instead of updating the whole input via ajax, this will just send a jQuery Javascript to be executed in the AjaxResponse. You can then just do the Javascript call in the page you linked and the adding of the css class will be done on client side.
The only thing you need is the id of your input so that jquery can find it. So setOutputMarkupId must be set to true and you can then get the id that wicket created by calling getMarkupId() and insert it into the javascript command.
As I already said it seems strange to me that you add the error-class in the onUpdate method. The correct way would seem to me to add the error class in the onError method (called when input is invalid) and remove it in the onUpdate (when input is valid).
val_op.setOutputMarkupId(true);
val_op.add(new OnChangeAjaxBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget art) {
art.appendJavaScript("$('#"+val_op.getMarkupId()+"').removeClass('field-error');");
}
#Override
protected void onError(AjaxRequestTarget art, RuntimeException e) {
art.appendJavaScript("$('#"+val_op.getMarkupId()+"').addClass('field-error');");
}
}
Related
I use Wicket 1.5
When i change color it is really changed on the page only after refreshing using F5. How to refresh it in backend?
I use this lines for changing color:
dateDescription.add(AttributeModifier.replace("style", "color:red;"));
add(dateDescription);
UPDATE #1
Now i use AJAX but still have to refresh page for changing color. Could you tell me what i did wrong?
// in page class
public class FilterUpdateBehavior extends AjaxFormComponentUpdatingBehavior {
public FilterUpdateBehavior(String event) {
super(event);
}
#Override
protected void onUpdate(AjaxRequestTarget target) {
RefreshResult result = getResult(target);
if (result.getStatus() == RefreshResultStatus.DATE_NOT_SET) {
dateIntervalFilterPanel.setAlarmDateStatus(true);
} else {
dateIntervalFilterPanel.setAlarmDateStatus(false);
}
}
}
// in date panel class
dateDescription.add(new AttributeModifier("style", new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
#Override
public String getObject() {
String cssClass = null;
if (isAlarmDateStatus()) {
cssClass = "color:red;";
} else {
cssClass = "color:black;";
}
return cssClass;
}
}));
add(dateDescription);
UPDATE #2
public RefreshResult getResults(AjaxRequestTarget target) {
// ... somewhere here additional logic of getting particulate RefreshResult
target.add(table);
target.add(paging);
target.add(loadingPanel);
return new RefreshResult(resultType);
}
UPDATE #3 FINAL (IT HELPED ME)
I miss this code line when i change isAlarmDateStatus, now it works fine. Thanks to Andrea!
target.add(dateDescription);
your code line looks right but you must use AJAX to reflect your changes without reloading the entire page. Unfortunately Wicket 1.5 is really outdated and there are few resources online to provide you an example of AJAX support. You might try to look into the old 1.5 AJAX examples code here:
https://github.com/apache/wicket/tree/build/wicket-1.5.17/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin
I have my string variable I want to display
final String wrongPw = "Wrong Password";
My AJAX yes button:
AjaxButton yesButton = new AjaxButton("yesButton", yesNoForm) {
private static final long serialVersionUID = -3827487963204274386L;
#Override
protected void onSubmit(AjaxRequestTarget target, Form form) {
if (target != null && password.equals(getPw())) {
answer.setAnswer(true);
modalWindow.close(target);
}else if(target != null && !password.equals(getPw())){
answer.setAnswer(false);
wrongPW.setVisible(true);
}
}
};
Further down:
wrongPW.setVisible(false);
add(wrongPW);
When I hit the yes button I must refresh the page for the wrongPW to display.
How can this be done dynamically?
You have to add the component you want to update to the target like this:
target.add(wrongPW);
Be sure to set the markup placeholder tag on initialization of the component you want to dynamically change the visibility of, else Wicket won't find it.
wrongPW.setOutputMarkupPlaceholderTag(true);
The reasons for this are explained here: https://stackoverflow.com/a/9671796/2795423
The following code attaches a new element with every subsequent click on the 2nd div. With each adding, the focus is set to the added element, so that it is ready for blur methods (I am setting the tabIndex attribute just for this purpose).
However, on clicking outside the new element, nothing happens, even though there should be a pop-up. Can anyone tell me what's wrong with this code?
public void onModuleLoad() {
VerticalPanel vert = new VerticalPanel();
String foo = "<div id ='foo'>Foo</div>";
$("#bodywrapper").append(foo);
$("#bodywrapper").append("<div id ='boo'>Boo</div>");
$("#boo").click(new Function() {
public boolean f(Event e) {
// Window.alert("foo");
$("<div id ='goo' tabIndex = '1'>Boo</div>").appendTo("#bodywrapper").focus();
return true;
}
});
$("#goo").live("blur", new Function() {
public boolean f(Event e) {
Window.alert("Foo");
return true;
}
});
RootPanel.get().add(vert);
}
}
The blur and focus events don't work with event delegation (live or delegate methods) because they're not bubbling events. JQuery introduce the special events focusout and focusin for this purpose. But GwtQuery doesn't support them yet. Please open an issue there and they will be implemented
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.
I have two swing ui forms and a module that they both look at.
Each ui is adding a listener to the change of an attribute
and update its own textfield when a change occurs.
basiccaly - they both should update the module and be update from it.
Is there a way simple to do it whithout a binding framework
Here is how I do it (but I keep getting attempt to mutate in notification ) -
On the update of my textField
myTextField.getDocument().addDocumentListener(new TFDocumentListener() {
protected void userChangedTF() {
Float value = myTextField.getValue();
if (value != null) {
myObj.setMyAttribute(value);
}
}
});
still in the ui - registering the change
myObj.addMyAttributeChangedListener(new ValueChangeListener<Float>() {
#Override public void valueChanged(Float value) {
if (!myTextField.isFocusOwner()) {
myTextField.setValueIn(value);
}
}
});
in the module - when setMyAttribute occurs - it calls this function
private void notifyIntervalChanged(float newValue) {
for (ValueChangeListener valueChangeListener : intervalChangedListenersList) {
valueChangeListener.valueChanged(newValue);
}
}
and I declared
public interface ValueChangeListener<T> {
void valueChanged(T Value)
}
If you need to change content of the same JTextComponent in the listener wrap the change (e.g. setText()) in the SwingUtilities.invokeLater()