public void onInit() {
super.onInit();
form.add(nameField);
form.add(checkbox);
// NB: when using form.submit() the submit button cannot be
// called 'submit'. If it is, the browser is likely to throw a JS exception.
checkbox.setAttribute("onclick", "form.submit()");
...
// NB: Bind the submit button. If it wasn't clicked it means the Form was submitted
// using JavaScript and we don't want to validate yet
ClickUtils.bind(submit);
// If submit was not clicked, don't validate
if(form.isFormSubmission() && !submit.isClicked()) {
form.setValidate(false);
}
submit.setActionListener(new ActionListener() {
public boolean onAction(Control source) {
// We can safely call isValid from within the submit action handler
// since validation is always active if the submit button was clicked
if (form.isValid()) {
addModel("msg", "Form is valid after validation");
}
return true;
}
});
}
public class MyPage extends BorderPage {
protected static final String HTML_IMPORT =
"<link rel=\"stylesheet\" type=\"text/css\" src=\"{0}/js/mylib.css\"/>\n"
+ "<script type=\"text/javascript\" src=\"{0}/js/mylib.js\"></script>\n"
+ "<script type=\"text/javascript\">alert('Hello World!');</script>\n";
public String getHtmlImports() {
String[] args = { getContext().getRequest().getContextPath() };
return MessageFormat.format(HTML_IMPORTS, args);
}
}
After:
public class MyPage extends BorderPage {
public List getHeadElements() {
// Cater for stateful pages. If you don't use stateful pages you don't need this check
if (headElements == null) {
headElements = super.getHeadElements();
headElements.add(new CssImport("/js/mylib.css"));
headElements.add(new JsImport("/js/mylib.js"));
JsScript script = new JsScript();
script.setContent("alert('Hello World!');");
headElements.add(script);
}
return headElements;
}
}
import org.apache.click.extras.control.DateField;
...
DateField dateField = new DateField("date");
with this:
import net.sf.click.extras.control.CalendarField;
...
DateField dateField = new CalendarField("date");
CalendarField subclasses DateField so the above snippet is valid.
See the Click Calendar
project for more details.
table.add(new Column("name")).setSortable(true);
form.add(new TextField("firstname")).setValue("Bob");
If you created a custom Form, FieldSet or Table and overrode the add
or addColumn method, you will be forced to return the methods argument.
For example if you had:
public class MyTable {
public void addColumn(Column column) {
...
}
}
you will need to update as follows:
public class MyTable {
public Column addColumn(Column column) {
...
// You must return the column
return column;
}
}
public class HtmlTable extends AbstractControl {
...
public String toString() {
int estimatedControlSize = 1000;
HtmlStringBuffer buffer = new HtmlStringBuffer(estimatedControlSize);
// Rendering Start
buffer.elementStart("table");
appendAttributes(buffer);
buffer.elementClose();
renderRows(buffer);
buffer.closeElement("table");
// Rendering End
return buffer.toString();
}
}
to this:
public class HtmlTable extends AbstractControl {
...
public void render(HtmlStringBuffer buffer) {
// Rendering Start
buffer.elementStart("table");
appendAttributes(buffer);
buffer.elementClose();
renderRows(buffer);
buffer.closeElement("table");
// Rendering End
}
public String toString() {
int estimatedControlSize = 1000;
HtmlStringBuffer buffer = new HtmlStringBuffer(estimatedControlSize);
render(buffer);
return buffer.toString();
}
}
Note, the code between the commented section, was moved from toString to the render method.
Also note that invoking a Control's toString()
method still outputs the same HTML representation, as toString() delegates to the
render
method.
Please note a common problem when overriding render in custom components, is
invoking super.toString() in order to render the Control's default
markup:
public class CustomField extends Field {
...
public void render(HtmlStringBuffer buffer) {
String field = super.toString(); // BEWARE this line will cause StackOverflowError
...
}
public String toString() {
HtmlStringBuffer buffer = new HtmlStringBuffer();
render(buffer);
return buffer.toString();
}
}
The highlighted line above will cause a StackOverflowError, meaning an infinite
loop was encountered. The reason for the error will become obvious when
tracing the sequence of calls:
public class CustomField extends Field {
...
public void render(HtmlStringBuffer buffer) {
super.render(buffer); // NOTE StackOverflowError won't occur
...
}
public String toString() {
HtmlStringBuffer buffer = new HtmlStringBuffer();
render(buffer);
return buffer.toString();
}
}
<click-app charset="UTF-8">
<pages package="org.apache.click.examples.page"/>
<log-service classname="org.apache.click.extras.service.JdkLogService"/>
</click-app>
While it is generally not recommended to use the Click LogService in your application code, you can retrieve it using the ClickUtils method
getLogService().