With wicket-dnd, is it possible to use dropTop() / dropBottom() with HTML tables? If so, what should the selector be?
I have an HTML table created via a ListView and have had success with dropCentre("tr"), but this is the only drop option that appears to work. Ideally, I would like to use dropTopAndBottom() and see a horizontal divider between table rows which indicates the drop target.
Update:
Here's the relevant code, simplified for for brevity. The table in question has a label per row and is added to a form.
// Container class for Wicket DND
final WebMarkupContainer dataWrapper = new WebMarkupContainer("dataWrapper");
dataWrapper.add(new WebTheme());
final ListView<BinaryData> data = new ListView<BinaryData>("data", list) {
#Override
protected void populateItem(final ListItem<BinaryData> item) {
final BinaryData data = item.getModelObject();
item.add(new Label("label", data.getLabel()));
}
#Override
protected ListItem<BinaryData> newItem(final int index, final IModel<BinaryData> itemModel) {
final ListItem<BinaryData> item = super.newItem(index, itemModel);
item.setOutputMarkupId(true);
return item;
}
};
dataWrapper.add(data);
dataWrapper.add(new DragSource(Operation.MOVE) {
#Override
public void onAfterDrop(final AjaxRequestTarget target, final Transfer transfer) {
}
}.drag("tr"));
dataWrapper.add(new DropTarget(Operation.MOVE) {
#Override
public void onDrop(final AjaxRequestTarget ajaxTarget, final Transfer transfer, final Location location) {
}
}.dropTopAndBottom("tr"));
form.add(dataWrapper);
And the markup:
<div wicket:id="dataWrapper">
<table>
<tbody>
<tr wicket:id="data">
<td wicket:id="label"></td>
</tr>
</tbody>
</table>
</div>
I am using Wicket-DND 0.6.0 and Wicket 6.6.0. When I drag a row using this code, I get the red cross icon displaying in the drag indicator.
wicket-dnd uses standard css selectors to determine drop locations.
The following is the modified TableExample in wicket-dnd-examples:
table.add(new DropTarget(Operation.MOVE)
{
#Override
public void onDrop(AjaxRequestTarget target, Transfer transfer, Location location)
throws Reject
// something was dropped
{
}.dropTopAndBottom("tr");
My problem was caused not by Wicket DND but by a apparently conflicting reference to JQuery UI in my markup (JQuery UI isn't required for Wicket DND, but was present for other components of my application).
Replacing this with a WiQuery-provided reference no longer results in any issues:
#Override
public void renderHead(final IHeaderResponse response) {
super.renderHead(response);
// Ensure that Wicket's jQuery library is always loaded, so we can invoke our own jQuery calls
response.render(JavaScriptReferenceHeaderItem.forReference(getApplication().getJavaScriptLibrarySettings().getJQueryReference()));
response.render(JavaScriptReferenceHeaderItem.forReference(CoreUIJavaScriptResourceReference.get()));
}
Related
I have wicket component with onClick event where I'd like to run javascript code which:
reloads the page
after page has been reloaded, scroll down to the markupId which was clicked
I have to pass as parameter the "markupId" value from wicket to javascript to find out to which position should I scroll down
WicketComponent.java
MyPanel div = new MyPanel("div");
div.add(new AjaxEventBehavior("click") {
#Override
protected void onEvent(AjaxRequestTarget target) {
// some requests...
String markupId = div.getMarkupId();
target.appendJavaScript("window.location.reload();");
target.appendJavaScript(jsReload(markupId));
}
div.add(AttributeModifier.replace("onclick", "clicked('" + div.getMarkupId() + "');"));
#Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptReferenceHeaderItem.forReference(new JavaScriptResourceReference(this.getClass(), "script.js")));
}
WicketComponent.html
<div wicket:id="div" onclick="clicked('markupId');">Text</div>
script.js
function clicked(markupId) {
window.location.reload();
}
document.addEventListener("DOMContentLoaded", function (event) {
let elementOffset = $("#{markupId}").offset().top; // how to pass here markupId parameter from wicket ?
let windowOffset = $(window).scrollTop();
window.scrollTo(0, elementOffset- windowOffset);
});
how to pass parameter "markupId" in javascript file which was attached in renderHead() or may be there is another solution for this ? I'll appreciate any help. Thanks!
you should solve your problem using location hash as described here:
Can we have code after location.reload(true)?
for the hash value use a fixed markup id for your component, something like:
div.setMarkupId("myMarkupId");
div.add(new AjaxEventBehavior("click") {
#Override
protected void onEvent(AjaxRequestTarget target) {
// some requests...
String markupId = div.getMarkupId();
target.appendJavaScript("window.location.hash = 'myMarkupId'");
target.appendJavaScript("window.location.reload();");
//that's it! no other js is needed
}
}
I haven't tried it but after page reloading it should scroll down to your component.
I'm trying to update my data widget from a CellTable to DataGrid and I basically thought I online a change from #UiField CellTable<T> to #UiField DataGrid<T> but thats not it.
private void init() {
sortHandler = new ListHandler<GWTUser>(getUsers());
dataGrid.setWidth("100%");
dataGrid.setHeight("100%");
dataGrid.setAutoHeaderRefreshDisabled(true);
dataGrid.setEmptyTableWidget(emptyDb);
dataGrid.addColumnSortHandler(sortHandler);
dataGrid.setVisibleRangeAndClearData(dataGrid.getVisibleRange(), true);
dataGrid.setRowCount(1, true);
dataGrid.clearTableWidth();
dataGrid.redraw();
// Setup Cell Table.
initCellTable();
// Connect the table to the data provider.
dataProvider.addDataDisplay(dataGrid);
}
private void initCellTable() {
// userId Column
TextColumn<GWTUser> userIdColumn = new TextColumn<GWTUser>() {
#Override
public String getValue(GWTUser object) {
return object.getUserId();
}
};
dataGrid.addColumn(userIdColumn, Lang.LABEL_USER_USERID);
dataGrid.addColumnSortHandler(sortHandler);
dataGrid.getColumnSortList().push(userIdColumn);
dataGrid.getColumnSortList().push(userIdColumn);
}
#Override
public void setUserList(List<GWTUser> users) {
setUsers(users);
dataGrid.setRowCount(getUsers().size(), true);
dataGrid.setRowData(0, getUsers());
dataGrid.setPageSize(getUsers().size());
dataGrid.setVisibleRange(new Range(0,dataGrid.getRowCount()));
dataGrid.redraw();
sortHandler.setList(getUsers());
}
uiBinder:
<g:VerticalPanel>
<g:ScrollPanel ui:field="listScrollPanel">
<c:DataGrid styleName= ui:field='dataGrid' width="100%" height="98%"/>
</g:ScrollPanel>
<g:HorizontalPanel>
<g:Button ui:field="createButton">New</g:Button>
<g:Button ui:field="refreshButton">Refresh</g:Button>
<g:Button ui:field="removeSelectedButton">Delete Selection</g:Button>
</g:HorizontalPanel>
</g:VerticalPanel>
When I change the region where my DataGrid should be with the chrome dev tool, the data with the tables is there but not shown.
as basic information: init is called by the constructor and setUserList is called in my activitiy when I get the data from a rest service. thanks for any help.
The DataGrid requires an explicitly set height. This means that you can't use percentages (e.g. 100%), but rather have to use something like 500px.
Here is a related question:
GWT DataGrid automatic height
I have a ListView which shows some panels. Because this ListView can be long, I want to make it collapsible.
For this purpose I added a WebMarkupContainer:
final WebMarkupContainer wmc = new WebMarkupContainer("listViewContainer");
wmc.setOutputMarkupId(true);
this.add(wmc);
This is how the ListView is created:
final ListView<String> examListViewSignedUp = new ListView<String>("examLVsu", signedUpExams) {
private static final long serialVersionUID = -2828116887162006658L;
protected void populateItem(ListItem<String> item) {
String examId = item.getModelObject();
item.add(new ExamPanel("exam1", examId));
}
};
wmc.add(examListViewSignedUp);
Finally, I add the AjaxLink. That is, in fact, a "[-]" if the list is expanded and a "[+]" otherwise. I "expand"/"collapse" the ListView by setting it's visibility via .setVisible(...).
final Model<String> sulink = new Model<String>(esuclt);
wmc.add(new AjaxLink("overviewCollapseLinkSignedUp") {
private static final long serialVersionUID = 8603181768552484977L;
#Override
public void onClick(AjaxRequestTarget target) {
if (examListViewSignedUp.isVisible()) {
examListViewSignedUp.setVisible(false);
sulink.setObject("[+]");
} else {
examListViewSignedUp.setVisible(true);
sulink.setObject("[-]");
}
target.add(wmc);
}
}.add(new Label("oclt1", sulink)));
Markup:
<wicket:container wicket:id="listViewContainer">
<h1 class="ocl">
<a wicket:id="overviewCollapseLinkSignedUp" href="#"><span wicket:id="oclt1">[?]</span></a>
<wicket:message key="examsHeadingInOverviewSignedUp">Exams - Signed Up</wicket:message>
</h1>
<span wicket:id="examLVsu"> <span wicket:id="exam1"></span></span>
</wicket:container>
My problem now is that the MarkupContainer isn't refreshed when clicking on the link. Nothing happens, but when I then reload the page, everything looks as expected. I searched for similar problems, but I wasn't able to find my mistake.
You cannot update <wicket:container>'s via Ajax, since they are not present in the final markup.
Use a normal <div wicket:id="listViewContainer"> instead.
I'm a noob to Wicket and trying to change the text of a AjaxButton on submit. So the idea is that the for the first time the page loads, the user sees an AjaxButton labeled e.g. "1", after clicking the button, the label of the button changes to "2" and after the next click to "3" and so on...This can't be hard, but as I said, I'm a noobie when it comes to wicket. All help appreciated!
form.add(new AjaxButton("ajax-button", form)
{
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form)
{ //how to change Button label here?
}
}
The answer is simple: use a model.
//counter field declared in page class
private int counter;
...
form.add(new AjaxButton("ajax-button", new PropertyModel<String>(this,
"counter", form)) {
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
counter++;
target.addComponent(this);
}
});
This is probably the most important rule of Wicket: when you need something changing, use a model. This takes some time getting used to, especially if you have experience with more "traditional" frameworks, and haven't used Swing either.
N.b.: keeping the counter in your page class may not be a good idea, but the general idea is the same.
Additionally to biziclop's answer, here is a solution for text with changing parameter.
In your java code:
AjaxButton yourButton = new AjaxButton("btnId"){
//your button's implementation goes here
};
int yourVariable = 42;
Label yourLabel = new Label("labelId", new Model<String>() {
public String getObject() {
String text = MessageFormat.format(new Localizer().getString("IdForLocalizerInYourLocalizerFile", null), yourVariable);
return text;
}
})
yourButton.add(yourLabel);
In your html:
<a type="submit" wicket:id="btnId">
<span wicket:id="labelId">[This text will never be seen, will be replaced by "The var..."]</span>
</a>
Finally your localization file will contain a line like:
IdForLocalizerInYourLocalizerFile= The variable's value is {0}. It will be replaced whenever it changes and button component is added to target. Text will remain.
I have a Page with a Wizard component. The user can navigate the panels of the wizard by using the next and previous buttons which I have performing full (non-ajax) form submissions so that the app is back-button friendly.
When the next button is clicked, I would like to attempt ajax form validation (if javascript is enabled). I tried doing:
nextButton.add( new AjaxFormValidatingBehavior( form, "onsubmit") );
to add such validation. The behaviour works - however, when validation errors occur the browser still submits the entire form.
What is the Wicket way to prevent the browser from submitting the form in this case?
Override the onError() method on either the form or the AjaxFormValidatingBehavior. If you do it on the behavior, I am not sure if that will prevent the form from submitting or not.
new AjaxFormValidatingBehavior( form, "onsubmit") {
public void onSubmit() {}
public void onError() {}
}
Maybe a bit to late but here is the answer:
public class SomePage extends WebPage {
private FeedbackPanel feedbackMessageError = new FeedbackPanel("feedbackTabAddEmpMesError", new ExactLevelFeedbackMessageFilter(FeedbackMessage.ERROR));
public SomePage(String id) {
final Form<Void> form = new Form<>("tabFormAddEmp");
add(form);
//Name textfield cannot be empty
final FormComponent<String> tabAddEmpName = new RequiredTextField<>("tabAddEmpName", Model.of(""));
tabAddEmpName.setLabel(Model.of("Name"));
tabAddEmpName.setOutputMarkupId(true);
//Salarynumber has to be minimal 10 char long
final FormComponent<String> tabAddEmpLoon = new RequiredTextField<>("tabAddEmpLoon", Model.of(""));
tabAddEmpLoon.add(new StringValidator(10, null)).setLabel(Model.of("Salarynumber"));
tabAddEmpLoon.setOutputMarkupId(true);
final Button button = new Button("tabFormAddEmpBut");
form.add(tabAddEmpName , tabAddEmpLoon, button);
button.add(new AjaxFormValidatingBehavior(form, "onclick") {
#Override
public void onError(AjaxRequestTarget target) {
//Add feedbackpanel to your html and voila!
target.add(feedbackMessageError);
}
#Override
protected void onSubmit(AjaxRequestTarget target) {
//Do some logic over here
}
}
}
}