I have a problem with validation on form actually sub-form.
In my website I have some kind of table and "Add row" button (BlockingAjaxSubmitLink).
When I try add let say 2 rows, I get validation error (because row in this table has Required=True parameter) and I can't add another row. I tried use simple AjaxLink but it doesn't have reference to form in onClick method and when I complete some rows and click "Add row" this data get lost.
I want to enable validation only after "save" button click.
Any idea how to deal with this problem?
I do something like you want using an AjaxLink.
My AjaxLink:
private AjaxLink addNewRow = new AjaxLink("addNewRow") {
#Override
public void onClick(AjaxRequestTarget target) {
MyEntityObject newTableRowObject = new MyEntityObject(irrelevantParameter);
entityObjectTableService.createNewRowInDB(newTableRowObject );
target.add(listViewContainer);
}
};
In this code the listViewContainer is a WebMarkupContainer which contains a ListView holding the table rows.
When i click this AjaxLink a new object representing a row in my table is added to the database and then the container containing the ListView is being refreshed refreshing the ListView and the new empty object is being fetched from the DB and shown as a new row in my table at the end.
Depending on your structure maybe you are looking after disabling validation using setDefaultFormProcessing(true); - http://ci.apache.org/projects/wicket/apidocs/6.x/org/apache/wicket/markup/html/form/AbstractSubmitLink.html#setDefaultFormProcessing%28boolean%29
For now I write some kind of hack
First I set
addKnowledgeLink.setDefaultFormProcessing(false);
and next
BlockingAjaxSubmitLink<Object> addKnowledgeLink = new BlockingAjaxSubmitLink<Object>(
"link_knowledge_add") {
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
ChangeDataForm.this.process(this);
/* some code */
target.add(form.get(MY_CONTAINER_ID));
}
(...)
and my hack...
//HACK
public void process(IFormSubmitter object){
if (!isEnabledInHierarchy() || !isVisibleInHierarchy())
{
return;
}
// run validation
validate();
/*if (hasError())
{
// mark all children as invalid
markFormComponentsInvalid();
// let subclass handle error
callOnError(object);
}
else
{*/
// mark all children as valid
markFormComponentsValid();
// before updating, call the interception method for clients
beforeUpdateFormComponentModels();
// Update model using form data
updateFormComponentModels();
// validate model objects after input values have been bound
onValidateModelObjects();
if (hasError())
{
callOnError(object);
return;
}
// Form has no error
delegateSubmit(object);
//}
}
and I ovveride one method
#Override
protected void onError(){
super.onError();
this.updateFormComponentModels();
}
I know it is ugly solution but I couldn't figure out anything better..
And I couldn't shutdown feedback messages
Related
I'm probably doing something else wrong but I've followed examples given here:
How to remove a row from the Cell Table
and
GWT get CellTable contents for printing or export
to accomplish my goal and the result is close but not quite right.
I have a page with two widgets. The first wiget contains a CellTable that uses an aSync ListDataProvider to pull results and populate a table. The table has a selection change event handler associated with it that loads further details about the selected item into the second widget below it.
public OrderAdminTable() {
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
OrderAdminListProxy selected = selectionModel.getSelectedObject();
if (selected != null && orderSnapShot != null) {
orderSnapShot.loadSnapShot(selected);
}
}
});
initTable();
this.addStyleName("order-list fixed_headers BOM");
this.setSelectionModel(selectionModel);
}
Once the second widget has loaded the details about the selected item, the user can remove the item from the table/list by clicking a button in the RootPanel that is the parent of both widgets.
searchView.getCmdReview().addClickHandler(new ClickHandler() {
#Override public void onClick(ClickEvent event) {
searchView.getOrderAdminSnapshot().reviewOrder();//this line calls a web service that deletes the item from the server data
dataProvider.getList().remove(searchView.getOrderAdminSnapshot().getSelectedOrder());
for(int i=0;i<table.getRowCount();i++){
TableRowElement row = table.getRowElement(i);
for(int j=0;j<row.getCells().getLength();j++){
if(row.getCells().getItem(j).getInnerText().contains(searchView.getOrderAdminSnapshot().getSelectedOrder().getSalesOrderNumber())){
row.setAttribute("removed", "true");
row.addClassName("hidden");
}
}
}
}
});
This all works fine until you select another item in the table. When that happens, the selection change event seems to redraw the table and remove my custom attribute and class from the previously selected item. This makes it appear in the list again.
The ultimate goal here is to avoid a round trip to the server to pull new results when you remove an item from the list. The line "searchView.getOrderAdminSnapshot().reviewOrder();" makes a web service call that removes the item from the data on the server side so it does not appear in subsequent reloads.
Is there some way to force the selection change event to maintain the state of the table row that was previously selected? Is there a better way to remove the selected item from the list? Any advice would be appreciated.
Once you remove the object from the list dataProvider.getList().remove, it should disappear from the table. There is no need to hide the row - this row should be gone. So your loop should never find it.
I'm using an AjaxFormComponentUpdatingBehavior to do some stuff when a choice is selected from an AutoCompleteTextField. After that stuff is done I want to clear the field but it's not behaving the way I expected it to.
Here're the relevant bits of code:
final AutoCompleteTextField<String> searchField =
new AutoCompleteTextField<String>(id, model);
searchField.add(new AjaxFormComponentUpdatingBehavior("onchange")
{
#Override
protected void onUpdate(AjaxRequestTarget target)
{
// Do stuff with the selected value here
...
searchField.clearInput();
target.addComponent(searchField);
}
});
I'm putting the value in a ListView and adding that to the target also. It gets updated correctly but the AutoCompleteTextField doesn't.
I think your example doesn't work, because you rerender the component on the client side using the model on the server side. If you reset the model value and repaint the component it has to work.
searchField.setModelObject(null);
target.addComponent(searchField);
However it is not neccessary to render the whole component, just clear the value on server and client side is enough.
The following example clears the model object and reset the field value by javascript (jQuery).
final AutoCompleteTextField<String> searchField =
new AutoCompleteTextField<String>(id, model);
searchField.setOutputMarkupId(true);
searchField.add(new AjaxFormComponentUpdatingBehavior("onchange")
{
#Override
protected void onUpdate(AjaxRequestTarget target)
{
// Do stuff with the selected value here
...
searchField.clearInput();
searchField.setModelObject(null);
target.appendJavascript("$('#" + searchField.getMarkupId() + "').val('');");
}
});
If you are using Wicket prior 6.x then the jQuery is not included. You can use the following JS:
target.appendJavascript("document.getElementById('" + searchField.getMarkupId() + "').value = '';");
Im populating a table using ListView component in wicket.The last column of my table is button. So for each row I'll have a button in the last column.What I'm trying to implement is onlick of the button I need to delete the appropriate row. So for this I need to get the current index of the list on click of button. How to achieve/get this ?
I would extend Ajax button and pass the row reference (item) in the constructor...then you can do anything you want..by overriding the onSubmit method
Example:
private class SpecialButton extends AjaxButton {
final Item<Object> rowItem;
public SpecialButton(final String id, final Item<Object> rowItem) {
super(id);
this.rowItem = rowItem;
}
#Override
protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
// here you cand do everything you want with the item and the model object of the item.(row)
Object object = rowItem.getModelObject();
}
}
You should replace Object from Item<Object> with your reapeater model. After creating this private class you can reuse it for every row in your repeater.
If you want to delete that row you just have to remove the model from the list used to generate the repeater and refresh the repeater container(Wicket does not allow you to refresh the repeater by adding it to the target...instead you have to add the repeater continer.)
Have a look at the repeaters Wicket Examples page to understand how to use ListView and other repeaters:
http://www.wicket-library.com/wicket-examples/repeater/
You can get the current index of the list from item.getIndex()
protected void populateItem(final ListItem<T> item) {
int index = item.getIndex();
...
Look here for inspirations on how to do it properly (without index):
Wicket ListView not refreshing
I'm creating a custom implementation of the GWT Header<String> class for use on a DataGrid Column that also uses a ListHandler to sort the data in this column. I'm attempting to handle and cancel Browser events in the Header class such that if a user clicks on a particular <INPUT> Element rendered by this custom Header object, we prevent the "mousedown" Event from bubbling back up to the DataGrid's event handler(as this incorrectly triggers the ListHandler's column sorting methods, preventing the user from entering data into the <INPUT> Element in question).
I'm able to successfully isolate the events whose bubble up we want to "cancel" by implementing a NativePreviewHandler in my Header class with the following code:
#Override
public void onPreviewNativeEvent(NativePreviewEvent event) {
final NativeEvent natEvent = event.getNativeEvent();
final Element element = natEvent.getEventTarget().cast();
final String eventType = natEvent.getType();
if ("mousedown".equals(eventType)) {
if (element.getTagName().equals("INPUT")) {
natEvent.preventDefault();
natEvent.stopPropagation();
event.cancel();
}
}
return;
}
Unfortunately no combination of the preventDefault(), stopPropagation(), or event.cancel() methods successfully stop the mousedown event from bubbling up to the parent DataGrid's handlers. When I attempted to debug this issue, I was able to confirm that although DOM.previewEvent method successfully called the DOM.eventCancelBubble and DOM.eventPreventDefault, the DOM.dispatchEvent method was still fired and ultimately triggered the DataGrid.fireEvent and a ColumnSortEvent.
Any guidance/approaches to prevent the GWT DataGrid from resorting itself if a particular portion of a custom Header is clicked would be greatly appreciated!
You can prevent the sorting of columns on Header click, with the following code snippet, by overriding onBrowserEvent2 API of DataGrid.
#Override
protected void onBrowserEvent2( Event event )
{
EventTarget eventTarget = event.getEventTarget();
if ( !Element.is( eventTarget ) )
{
return;
}
final Element target = eventTarget.cast();
String id = target.getId();
if ( id != null && id.equals( COLUMN_HEADER_ID ) )
{
return;
}
super.onBrowserEvent2( event );
}
I am using the following constructor to create a checkboxcell in an editable data grid.
CheckboxCell(false, true)
When I use this and click at any place in the row, selection change event does not fire and I am using single selection model .
When I use,
CheckboxCell();
Selection change event fires on the row but,
1) We have click twice to check or uncheck the cell.
2) if we check or uncheck in the checkboxcell, the value will reverted as soon as I click anywhere.
I am trying to figure out the solution, but not successful yet. Any help would be appreciated.
Am using GWT 2.4.0
The problem is because of selection if possible do not use selection model. and add field updater for the column of check box. I have used this:
Column< GridReportFields, Boolean > cb = new Column< GridReportFields, Boolean >(new CheckboxCell() ) {
#Override
public Boolean getValue(GridReportFields object) {
// TODO Auto-generated method stub
return object.getCheckb();
}
};
cb.setFieldUpdater(new FieldUpdater<GridReportFields, Boolean>() {
#Override
public void update(int index, GridReportFields object, Boolean value) {
// TODO Auto-generated method stub
object.setCheckb(value);
dataGrid.redraw();
}
});
here gridReport Field is my model class. and setCheckb is is setter for the boolean variable that holds the value of checkbox.