Skip to content

Instantly share code, notes, and snippets.

@nabil-hassan
Last active September 16, 2015 10:01
Show Gist options
  • Save nabil-hassan/20db1c07a132dfaab346 to your computer and use it in GitHub Desktop.
Save nabil-hassan/20db1c07a132dfaab346 to your computer and use it in GitHub Desktop.
GWT CompositeEditor Example
package net.nabilh.gwtsandbox.client.widgets.form.phone;
import com.google.gwt.core.client.GWT;
import com.google.gwt.editor.client.CompositeEditor;
import com.google.gwt.editor.client.EditorDelegate;
import com.google.gwt.editor.client.LeafValueEditor;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiConstructor;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import net.nabilh.gwtsandbox.shared.dto.PhoneNumberDTO;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
/**
* This widget implements {@link com.google.gwt.editor.client.CompositeEditor} to represent a
* list of {@link PhoneNumberField} widgets as rows, which the user can add to and remove from using embedded controls.<br/><br/>
* Author: Nabil Hassan <br/>
* Date: 08/09/2015 18:11 <br/>
*/
public class PhoneNumberListField extends Composite implements CompositeEditor<List<PhoneNumberDTO>, PhoneNumberDTO, PhoneNumberField>, LeafValueEditor<List<PhoneNumberDTO>> {
public static final Logger LOG = Logger.getLogger(PhoneNumberListField.class.getName());
interface Binder extends UiBinder<Widget, PhoneNumberListField> {}
private static Binder uiBinder = GWT.create(Binder.class);
private List<PhoneNumberField> rows = new ArrayList<PhoneNumberField>();
private CompositeEditor.EditorChain<PhoneNumberDTO, PhoneNumberField> editorChain;
private EditorDelegate<List<PhoneNumberDTO>> editorDelegate;
@UiField
Button addBtn, removeBtn;
@UiField
VerticalPanel panel;
private int sizeLimit;
@UiConstructor
public PhoneNumberListField(int sizeLimit) {
this.sizeLimit = sizeLimit;
initWidget(uiBinder.createAndBindUi(this));
panel.getElement().setAttribute("cellpadding", "5");
}
@Override
public PhoneNumberField createEditorForTraversal() {
LOG.finest("Creating new sub-editor for traversal");
return new PhoneNumberField();
}
@Override
public String getPathElement(PhoneNumberField phoneNumberField) {
LOG.finest("getPathElement() called for phoneNumberField: " + phoneNumberField);
return "[" + rows.indexOf(phoneNumberField) + "]";
}
@Override
public void setValue(List<PhoneNumberDTO> phoneNumberDTOs) {
LOG.finest("setValue() called on: " + editorDelegate.getPath());
// Clear and detach current sub-editor list.
if (rows != null && rows.size() > 0) {
LOG.finest("Clearing current sub-editor list of " + rows.size() + " rows");
for (PhoneNumberField row : rows) {
editorChain.detach(row);
}
rows.clear();
panel.clear();
}
// Setup the new editor chain.
if (phoneNumberDTOs != null) {
for (PhoneNumberDTO dto : phoneNumberDTOs) {
addPhoneNumberToList(dto, false);
}
}
}
@Override
public List<PhoneNumberDTO> getValue() {
LOG.finest("getValue() called on: " + editorDelegate.getPath());
List<PhoneNumberDTO> value = new ArrayList<PhoneNumberDTO>();
for (PhoneNumberField field : rows) {
value.add(editorChain.getValue(field));
}
LOG.finest("Returning a list of " + value.size() + " values");
return value;
}
@Override
public void setDelegate(EditorDelegate<List<PhoneNumberDTO>> editorDelegate) {
this.editorDelegate = editorDelegate;
}
@Override
public void setEditorChain(EditorChain<PhoneNumberDTO, PhoneNumberField> editorChain) {
this.editorChain = editorChain;
}
@Override
public void flush() {
// Not implemented
}
@Override
public void onPropertyChange(String... strings) {
// Not implemented
}
@UiHandler("addBtn")
public void handleClick_addBtn(ClickEvent event) {
addPhoneNumberToList(new PhoneNumberDTO(), true);
}
@UiHandler("removeBtn")
public void handleClick_removeBtn(ClickEvent event) {
if (rows != null && rows.size() > 0) {
PhoneNumberField phoneNo = rows.get(rows.size() - 1);
LOG.finest("Removing phone number: " + phoneNo);
editorChain.detach(phoneNo);
rows.remove(phoneNo);
panel.remove(phoneNo);
}
}
private void addPhoneNumberToList(PhoneNumberDTO dto, boolean enforceSizeLimit) {
// Prevent the user from adding further phone numbers when the size limit has been reached.
// N.B. the size limit is not enforced when called from setValue() (i.e. when loading).
if (enforceSizeLimit && rows.size() >= sizeLimit) {
Window.alert("Cannot add further phone numbers, size limit of: " + sizeLimit + " has been reached");
return;
}
LOG.finer("Adding sub-editor for phone number DTO: " + dto);
PhoneNumberField phoneNoField = new PhoneNumberField();
phoneNoField.setLabelText("Phone No " + (rows.size() + 1));
panel.add(phoneNoField);
rows.add(phoneNoField);
editorChain.attach(dto, phoneNoField);
}
}
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<g:VerticalPanel>
<g:HorizontalPanel spacing="5">
<g:Button ui:field="addBtn" text="Add Phone No"/>
<g:Button ui:field="removeBtn" text="Remove Phone No"/>
</g:HorizontalPanel>
<g:VerticalPanel ui:field="panel">
<!-- Phone Number Fields Will Be Attached Here -->
</g:VerticalPanel>
</g:VerticalPanel>
</ui:UiBinder>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment