Wicket: How to distinguish between render caused by certain ajax target and other renders - wicket

in my application wicket is the client server and I am having a problem,I have two scenarios where the wicket asks from the server for info
read
read after update
i need to distinguish between the two cases , i want somethnig like
READ_OR_READ_AFTER_UPDATE paramter = READ_OR_READ_AFTER_UPDATE.READ;
ajaxRequestTarget.add(compToRender,parmeter);
is there a way to send the component value and treat the value inserted in prior call inside this component getModel , or before render...

You can check whether the current request is Ajax by:
if (RequestCycle.get().find(AjaxRequestTarget.class) != null) { Ajax } else {non-Ajax}

I dont know if i understand you correctly. Maybe this is what you want:
In your component set a variable for this
public Boolean isUpdated = Boolean.FALSE;
In your method where you perform the "update" set this variable to Boolean.TRUE;
In your components onConfigure() method overide and perform what you want:
#Override
protected void onConfigure() {
super.onConfigure();
if (isUpdated){
//do this
} else {
//do that
}
}

Related

Wicket: AjaxRequestTarget vs onModelChanged

I'm working on a code in a wicket project, where the original devs used the onModelChanged() method quite a lot in Ajax request handling methods. I, for one, however am not a strong believer of this implementation.
In fact, I can't think of any examples, where calling the target.add(...) is inferior to calling the onModelChanged method.
Am I missing some key concepts here?
Example:
public MyComponent extends Panel {
public MyComponent(String id, Component... componentsToRefresh) {
add(new AjaxLink<Void>("someId") {
#Override
public void onClick(AjaxRequestTarget target) {
// some logic with model change
for(Component c: componentsToRefresh) {
c.modelChanged();
}
target.add(componentsToRefresh);
}
};
}
}
Now, there are a couple of things I don't agree with, the very first is the componentsToRefresh parameter, the second is (as the question suggests), the fact that we called c.modelChanged() on all components in that array. My guess would be that it is completely un necessary and instead of a parameter in the constructor, one should just write an empty function in MyComponent and override it, and put the necessary components in there when needed.
I would suggest to use Wicket Event system instead. That is, whenever the AjaxLink is clicked you will broadcast an event:
send(getPage(), Broadcast.BREATH, new MyEventPayload(target));
This will broadcast the event to the current Page and all its components.
Then in any of your components you can listen for events:
#Override
public void onEvent(IEvent event) {
Object payload = event.getPayload();
if (payload instanceof MyEventPayload) {
((MyEventPayload) payload).getTarget().add(this); // or any of my sub-components
event.stop(); // optionally you can stop the broadcasting
}
}
This way you do not couple unrelated components in your application.
See Wicket Guide for more information.

How to validate inputs and prevent save actions using databinding in eclipse?

I want to create input forms which validate user input and prevent the model from being saved with invalid data. I have been using databinding which works up to a point but my implementation is not as intuitive as I would like.
Imagine an input which contains '123' and the value must not be empty. The user deletes the characters one by one until empty. The databinding validator shows an error decoration.
However, if the user saves the form and reloads it, then a '1' is displayed in the field - i.e. the last valid input. The databinding does not transmit the invalid value into the model.
I have a ChangeListener but this is called before the databinding so at that point the invalid state has not been detected.
I would like the error to be displayed in the UI but the model remains valid (this is already so). Also, for as long as the UI contains errors, it should not be possible to save the model.
/**
* Bind a text control to a property in the view model
**/
protected Binding bindText(DataBindingContext ctx, Control control,
Object viewModel, String property, IValidator validator)
{
IObservableValue value = WidgetProperties.text(SWT.Modify).observe(
control);
IObservableValue modelValue = BeanProperties.value(
viewModel.getClass(), property).observe(viewModel);
Binding binding = ctx.bindValue(value, modelValue, getStrategy(validator), null);
binding.getTarget().addChangeListener(listener);
ControlDecorationSupport.create(binding, SWT.TOP | SWT.LEFT);
return binding;
}
private UpdateValueStrategy getStrategy(IValidator validator)
{
if (validator == null)
return null;
UpdateValueStrategy strategy = new UpdateValueStrategy();
strategy.setBeforeSetValidator(validator);
return strategy;
}
private IChangeListener listener = new IChangeListener()
{
#Override
public void handleChange(ChangeEvent event)
{
// notify all form listeners that something has changed
}
};
/**
* Called by form owner to check if the form contains valid data e.g. before saving
**/
public boolean isValid()
{
System.out.println("isValid");
for (Object o : getDataContext().getValidationStatusProviders())
{
ValidationStatusProvider vsp = (ValidationStatusProvider) o;
IStatus status = (IStatus)vsp.getValidationStatus()
.getValue();
if (status.matches(IStatus.ERROR))
return false;
}
return true;
}
Your best bet is to steer clear of ChangeListeners - as you've discovered, their order of execution is either undefined or just not helpful in this case.
Instead, you want to stick with the 'observable' as opposed to 'listener' model for as long as possible. As already mentioned, create an AggregateValidationStatus to listen to the overall state of the DataBindingContext, which has a similar effect to your existing code.
Then you can either listen directly to that (as below) to affect the save ability, or you could even bind it to another bean.
IObservableValue statusValue = new AggregateValidationStatus(dbc, AggregateValidationStatus. MAX_SEVERITY);
statusValue.addListener(new IValueChangeListener() {
handleValueChange(ValueChangeEvent event) {
// change ability to save here...
}
});
You can use AggregateValidationStatus to observe the aggregate validation status:
IObservableValue value = new AggregateValidationStatus(bindContext.getBindings(),
AggregateValidationStatus.MAX_SEVERITY);
You can bind this to something which accepts an IStatus parameter and it will be called each time the validation status changes.

Wicket: How to add substring to every error message?

We are using wicket 6.
Both Session and Component classes have error() method to display an error. However in both cases these methods are final.
Is there any other universal way to add postfix to any error message? (we are looking to add error id)
Edit:
We have hundreds of files of code which already uses error() method from both Session and Component, so massive refactoring is not an option.
You can add arbitrary message objects to a Wicket component:
component.error(new ErrorCode(code));
With a custom FeedbackPanel you can then display the error code as needed:
protected Component newMessageDisplayComponent(String id, FeedbackMessage message)
{
Serializable rawMessage = message.getMessage();
if (rawMessage instanceof ErrorCode) {
// create custom component to display a text and/or code
...
} else {
return super.newMessageDisplayComponent(id, message);
}
}

Send all data from row (not only changed) during update request from ListGrid in SmartGWT

Currently I'm trying to customize SmartGWT's DataSource to work with custom REST services. And I hit into problem with sending update requests when some changes have been made in the ListGrid row. By default only changed cells in the row are sent in update request (as described here). And I want to change this behavior to send all data from the row not just edited. I've already spent a lot of time figuring out how to do this but still can't find a solution. Could you please give me any advice how to change this OOTB behavior? Probably someone has had similar problem and found the solution.
//Override the transformRequest function in DataSource
//
#Override
protected void transformResponse(DSResponse response, DSRequest request,
Object data){
// On Update Operation call will hit the below condition
//
if (dsRequest.getOperationType().equals(DSOperationType.UPDATE)) {
// Get the data from listGird
//
listGrid.getDataAsRecordList()
//Set to request
//
dsRequest.setData();
}
}
Here is the way how I implement sending all data from the row during update request. Probably it will help someone.
I overrode transformRequest method and added there such code:
#Override
protected Object transformRequest(final DSRequest dsRequest) {
...
if (dsRequest.getOperationType = OperationType.UPDATE) {
...
final JavaScriptObject basicJSObject = dsRequest.getOldValues().getJsObj();
final JavaScriptObject latestChanges = dsRequest.getData();
JSOHelper.addProperties(basicJSObject, latestChanges);
// Regexp probably can be optimized
final String resultString = JSON.encode(responseData)
.replaceAll("[,]\\s*[,]", ",")
.replaceAll("^\\s*[,]", "")
.replaceAll("[,]\\s*$", "");
return resultString;
}
...
}

GWT - How to add more than 1 CellTables on the same page

I have a page using StackLayoutPanel.
In that 3 stacks requires separate CellTables.
Currently events I need to use are RangeChangeEvent, SelectionChangeEvent.
Now question is how to differentiate OnRangeChangeEvent from one another.
The source table is referenced by the event that you are catching. "event.getSource()"
always gives a reference to the object that caused the event.
For example, if you have three tables, and you attach the same handler as below:
RangeChangeEvent.Handler handler = new RangeChangeEvent.Handler() {
#Override
public void onRangeChange(RangeChangeEvent event) {
if(table1 == event.getSource()){
// first table
} else if (table2 == event.getSource()){
// second table
} else if (table3 == event.getSource()){
// third table
}
};
table1.addRangeChangeHandler(handler);
table2.addRangeChangeHandler(handler);
table3.addRangeChangeHandler(handler);
The above example assumes that there is no selection model specified on the tables. If there is, the selection model will be the source of the events.
Alternatively, you can just attach a table-specific handler to each table:
RangeChangeEvent.Handler handler1 = new RangeChangeEvent.Handler() {
#Override
public void onRangeChange(RangeChangeEvent event) {
// Handle stuff happening to table 1
}
};
RangeChangeEvent.Handler handler2 = new RangeChangeEvent.Handler() {
#Override
public void onRangeChange(RangeChangeEvent event) {
// Handle stuff happening to table 2
}
};
table1.addRangeChangeHandler(handler1);
table2.addRangeChangeHandler(handler2);
// And so on for any more tables
With this approach you won't need to worry about the event source, as you already know which handler corresponds to which table.
Were you setting the same event handlers for each CellTable? If so, don't. You can simply make a different handler for each CellTable. While it would theoretically be possible to detect the source as in filip-fku's example, it won't be if you are using SelectionModel.
Bottom line: you should not try to use the same handlers on multiple objects unless you absolutely have to.