Wicket: Validating nested forms inside DataTable component - forms

I'm currently testing the creation of a custom DataTable where I need to have a a panel with a form inside some of the table cells, with the following structure:
Outer form > DataTable (rows > cells > cell > panel > inner form)
At the moment, I am able to successfully submit these nested forms (inner forms inside each cell) with the submit button of an outer form, but the inner forms do not show the validation feedback messages (although I checked and they are being validated - the outer form goes to onError() on validation error).
I believe this problem is somehow related to the similar issue with ListView where I have to use setReuseItems(true) in order to be able to get the feedback messages. (Ref: wicket validate textfield inside listview can't see error message)
I have tried to configure the DataTable reuse item strategy, and even the DataTable inner datagrid (as from Wicket 6) reuse strategy, but still, I could not get the feedback messages. (Ref:
A GridView inside a Wizard in wicket fails to render error feedback messages)
I'm starting to think that I might not be able to this at the DataTable level, since the onPopulate() of the cells is really only called on the AbstractDataGridView level. Does anyone know then if validating these inner forms inside of a DataTable is possible and, if so, how can I achieve this?
Thanks for your time and attention.

I had the same problem and the way I solved it was like this:
Form<List<MyDataType>> form = new Form<List<MyDataType>>("form", getModel()) {
#Override
protected void onValidate() {
super.onValidate();
visitChildren(FormComponent.class, new IVisitor<FormComponent, Void>() {
#Override
public void component(FormComponent component, IVisit<Void> visit) {
component.processInput();
if (component.hasErrorMessage()) {
for (FeedbackMessage message :
component.getFeedbackMessages()) {
if (message.isError()) {
get(TABLE_ID).getFeedbackMessages().add(message);
}
}
}
}
});
}
};
So basically when ever I validate my Form, I manually check for inner FormComponents and check those. Then I forward the error messages to the table which has its own FeedbackPanel.
Probably not the most elegant solution, but it works.

table.setItemReuseStrategy(new ReuseIfModelsEqualStrategy()) set the trick for me
source:
1 wicket validate textfield inside listview can't see error message
2 A GridView inside a Wizard in wicket fails to render error feedback messages

Related

Custom Form Layout Validation

I want to have my own validation flow, with custom layout and message.
By default, the validation from the form builder put all the error message beside the input field. And it will validate all fields at once after submit.
I want to validate field by field after submitting, and error message is displayed in the same place for all the input fields (beside the submit button/on top of the form).
Currently I'm trying custom form layout with "ASCX" type. Is it possible to do all the validation in the back-end code ".cs"?
Or I must inject java script at the custom form layout design in source mode?
Or there is any better way to do it?
In HTML layout type you can place validation macros anywhere you need -> $$validation:FirstName$$
You can also specify a validation that executes without submitting the form - example -> http://devnet.kentico.com/articles/tweaking-kentico-(2)-unique-fields
Anyway, with the validation macro above you can move the error message wherever you want.
In your online form, go to Layout and enter your layout markup manually using HTML and the macros for form field values, labels and validation. There you can specify where all your form elements will go on the form, even the button.
If you want to have custom CS for your validation of that form, you're better off creating a custom event handler for the form before insert. See documentation below:
Custom event handler
Form Event handler
using CMS;
using CMS.DataEngine;
using CMS.OnlineForms;
using CMS.Helpers;
// Registers the custom module into the system
[assembly: RegisterModule(typeof(CustomFormModule))]
public class CustomFormModule : Module
{
// Module class constructor, the system registers the module under the name "CustomForms"
public CustomFormModule()
: base("CustomForms")
{
}
// Contains initialization code that is executed when the application starts
protected override void OnInit()
{
base.OnInit();
// Assigns a handler to the Insert.After event
// This event occurs after the creation of every new form submission
BizFormItemEvents.Insert.After += Insert_After;
}
private void Insert_After(object sender, CMS.OnlineForms.BizFormItemEventArgs e)
{
if (e.Item.TypeInfo.ObjectType.ToLower().Contains("bizform.codename"))
{
//do some work or form validation
}
}
}

how to avoid field disposed in a WizardPage

I have a Wizard , with two wizard Pages.
On each page I have controls, on page 2 I have some text fields,
in my controller I wanto to access them, like this:
f2.setCantSurcos(Integer.getInteger(wizard.getTxtCantsurcos()));
Where wizard method is a wrapper to page 2:
public String getTxtCantsurcos() {
return this.page2.getTxtCantsurcos();
}
The problem is that the method throw me this error:
" Widget is disposed"
I suppose this is because I'm tryin to access the widget directly:
public String getTxtCantsurcos() {
return txtCantsurcos.getText();
}
If i'm correct, I should move/copy the content of the Text field to a String attribute.
But, how to do that when the user click on Next Button ?
Best regards.
Nico
Don't try and wait for the next button to be clicked.
Use addModifyListener to add a modify listener to each text control and save the value in a string whenever the text is modified.
You can also use JFace 'data binding' for this sort of thing.
Since I cannot comment Greg's post, I post an answer:
Here is a snippet of a simple data binding example:
http://git.eclipse.org/c/platform/eclipse.platform.ui.git/plain/examples/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Snippet014WizardDialog.java

GWTP Presenter prepareFromRequest - load data into form retrieved from event

I have been trying GWTP for the past couple of weeks and building a small project with it.
Here's the question :
I have a grid widget (attached screenshot) which shows a list of data. On selection of a checkbox of a row and clicking on Edit Request, I get into a detail page.
Since I have all the data (model) to be shown in the detail page in the summary screen presenter itself, I don't want to fetch it from the database again.
So, I did the following :
On selection and clicking edit request, I get the selected model
Make a place request to the detail page
Fire an edit event and pass the selected model as parameter.
I understand that I am doing it wrong because when I select an item and hit Edit Request, the detail page does not receive the selected item yet. It just shows a blank page with no data filled in (obviously, because the place has been reached much before the event has been fired).
Current code :
RequestModel selectedItem = getView().getGrid().getSelectionModel().getSelectedItem();
PlaceRequest placeRequest=new PlaceRequest(NameTokens.initiationedit);
getEventBus().fireEvent(new RequestEditEvent(selectedItem, PHASE_INITIATION));
placeManager.revealPlace(placeRequest);
Personally thought solution : Instead of firing an event, I could make a placerequest with a parameter of the selected item's id and then override the useManualReveal and the prepareFromRequest to fetch data fresh from database.
But is there a way I could avoid database call for the pre-existing data.
If you want to keep your current "RequestEditEvent" solution, then make sure to use #ProxyEvent (see http://code.google.com/p/gwt-platform/wiki/GettingStarted?tm=6#Attaching_events_to_proxies).
Another possibility may be to invert the direction of the event: In your details presenter, fire an event which requests data from the overview presenter.
However, when using the same data across multiple presenters, then it may be a good idea to keep the data in a central model: Create a model class (#Singleton) and inject it everywhere you need it. Then you can make a lookup (by id) from that local model instead of asking the server. In this case, you don't need any events - just the id somewhere, e.g. as a place parameter, or even as a "currentItemId" in the model.
Based on the answer by #Chris Lercher, I used the ProxyEvent. The implementation details are as follows.
In my RequestEditPresenter (the details presenter), I implemented the event handler RequestEditHandler as in
public class RequestEditPresenter extendsPresenter<RequestEditPresenter.MyView, RequestEditPresenter.MyProxy> implements RequestEditHandler{
then in the same RequestEditPresenter override the method in the RequestEditHandler as in
#Override
#ProxyEvent
public void onRequestEdit(RequestEditEvent event) {
getView().setModelToView(event.getRequestModel());
...various other initiation process...
placeManager.revealPlace(new PlaceRequest(NameTokens.initiationedit));
}
Since the Details presenter was a Place, I used the placeManager. For presenters that do not have a NameToken, just call the forceReveal() method

How to remove a validator from a Select?

I have a form where I need to add/remove validators dynamically. Based on a dropdown selection, other form fields may have different validation rules.
For other kinds of inputs, I've used replace(methodThatCreatesTheInput()) to get rid of a previously added validator. (Not knowing of a better way. Specifically, there doesn't seem to be any way to directly remove a validator from a component...)
With Select, from wicket-extensions, this approach fails with something like:
WicketMessage: submitted http post value [[Ljava.lang.String;#5b4bf56d]
for SelectOption component [8:myForm:targetInput] contains an
illegal relative path element [targetConsortiums:1:option] which does not
point to an SelectOption component. Due to this the Select component cannot
resolve the selected SelectOption component pointed to by the illegal value.
A possible reason is that component hierarchy changed between rendering and
form submission.
The method that creates the Select:
private FormComponent<?> targetSelection() {
Map<Class<? extends Target>, List<Target>> targets = targetService.getAllAsMap();
SelectOptions<Target> propertyOptions = new SelectOptions<Target>("targetConsortiums",
targets.get(Consortium.class), new TargetRenderer());
SelectOptions<Target> consortiumOptions = new SelectOptions<Target>("targetProperties",
targets.get(Property.class), new TargetRenderer());
Select select = new Select(ID_TARGET, new PropertyModel<Target>(model, "target"));
select.add(propertyOptions);
select.add(consortiumOptions);
select.setRequired(true);
select.setMarkupId(ID_TARGET);
return select;
}
(Why use a Select instead of normal DropDownChoice? We want the two types of choices to be clearly separated, as documented in this question.)
Any ideas how to solve this? What I'm trying to achieve is, of course, very simple. Unfortunately Wicket disagrees, or I'm using it wrong.
Wicket 1.4.
I don't know how to do this on Wicket 1.4, but on Wicket 1.5 there is a remove method for validators on FormComponent (see javadoc)

Adding a form field that is not in the schema to Doctrine form Symfony 1.4

I have an image upload form and at the bottom, I'd like to have a checkbox that the user must check before submitting the form, certifying that they have the right to distribute the photo. I've tried adding it as a Widget in the Form class, but it is not displaying. What is the best way to accomplish this?
For validation, you can add this to your form class to allow fields outside the model:
$this->validatorSchema->setOption('allow_extra_fields', true);
$this->validatorSchema->setOption('filter_extra_fields', false); // true or false
Other than that, just adding the widget in the standard way should work fine.
Adding a new widget to your form should be the right way.
class ImageForm extends BaseImageForm
{
public function configure()
{
$this->widgetSchema['copyright'] = new sfWidgetFormInputCheckbox();
}
}
For conditional validation, check this cookbook page should still be valid.