webfirmframework for Java Experts
EventAttribute
Attributes which can execute JavaScript on some event are considered as event attributes. Eg :- onclick, onchange etc...
All event attributes in wffweb contain a common constructor containing four arguments which are used to handle events at client side and server side. See the below code sample
public class SampleCode extends Body {
public SampleCode() {
super(null);
develop();
}
private void develop() {
ServerAsyncMethod serverAsyncMethod = new ServerAsyncMethod() {
@Override
public WffBMObject asyncMethod(WffBMObject wffBMObject,
Event event) {
// the sourceTag from which the event generated
// in this sample sourceTag instance will be button1 instance
AbstractHtml sourceTag = event.getSourceTag();
// used to send data to the client
WffBMObject bmObject = new WffBMObject();
bmObject.put("someKey", BMValueType.STRING,
"こんにちは WebFirmFramework");
return bmObject;
}
};
String jsPreFunctionBody = "/* event and source keywords are implicit objects here */ /*may be on some condition*/ return true;";
//source is equivalent to event.srcElement
String jsFilterFunctionBody = "/* event and source keywords are implicit objects here */ var dataFromClient = {'clientKey' : 'clientValue', elementId : source.id, elementName : event.srcElement.name}; return dataFromClient;";
// jsObject is an implicit object
// which is a conventional representation of bmObject
String jsPostFunctionBody = "alert(jsObject.someKey);";
OnClick onClick = new OnClick(jsPreFunctionBody, serverAsyncMethod,
jsFilterFunctionBody, jsPostFunctionBody);
Button button1 = new Button(this, onClick);
}
}
In the above code,
OnClick
is an event attribute. There are four arguments for its constructor
jsPreFunctionBody
,
serverAsyncMethod
,
jsFilterFunctionBody
and
jsPostFunctionBody
.
jsPreFunctionBody
,
jsFilterFunctionBody
and
jsPostFunctionBody
can contain JavaScript function body without function declaration
and all these are executed at client side.
jsPreFunctionBody
should return boolean value. If it returns true then only
serverAsyncMethod
will be invoked. This will be useful when there is a validation
needs to be done at client side before invoking serverAsyncMethod
.
event
and source
are implicit objects in its scope.
source
is equivalent to event.srcElement
.
serverAsyncMethod
should be an instance of
ServerAsyncMethod
. ServerAsyncMethod#asyncMethod
invokes at server side.
asyncMethod
contains two arguments
wffBMObject
and
event
. The returned JavaScript object by
jsFilterFunctionBody
will be received as a
wffBMObject
.
The role of
jsFilterFunctionBody
is to provide data to
asyncMethod
. The
jsFilterFunctionBody
should return either a JavaScript object or null. This JavaScript
object will be converted to a
WffBMObject
which will be received as an argument in
asyncMethod
.
event
and source
are implicit objects in its scope.
source
is equivalent to event.srcElement
.
jsPostFunctionBody
is executed after
asyncMethod
is invoked. The role of
jsPostFunctionBody
is to receive data returned by
asyncMethod
. In the sample code,
asyncMethod
returns an object
bmObject
which will be converted to a JavaScript object, this JavaScript object be
available as an implicit object
jsObject
in the scope of
jsPostFunctionBody
.
action
object since 3.0.15
Since wffweb-3.0.15, there is one more object available in the scope of
jsPreFunctionBody
called action
.
This action
object has a function called perform()
,
it can do the same action which happens when
jsPreFunctionBody
returns true
.
Doing return true
in jsPreFunctionBody
or calling its action.perform()
does the same job.
The advantage of action.perform()
is the action
object can be passed to any other JavaScript code and invoke perform()
functionn later to do the same job.
You can call action.perform()
multiple times to do the same action multiple times.
However, if you are calling action.perform()
inside jsPreFunctionBody
the return true
has no effect on it because both do the same job.
This is to prevent double form submission.
Eg 1: Suppose there is a button on the UI, when we click on
the button it should request JavaScript notification permission
from user and send the value to the server. In this case, the
permission value is got asynchronously so have to use
action.perform();
as follows.
new Button(mainDiv,
new OnClick("""
Notification.requestPermission().then((perm) => {
source.notifPerm = perm;
action.perform();
});
return false;""", (data, event) -> {
String notifPerm = (String) data.getValue("notifPerm");
System.out.println("notifPerm = " + notifPerm);
WffBMObject result = new WffBMObject();
result.put("perm", BMValueType.STRING, notifPerm);
result.put("msg", BMValueType.STRING, "Notification " + notifPerm + "!");
return result;
}, "return {notifPerm: source.notifPerm};",
"if (jsObject.perm === 'granted') {new Notification(jsObject.msg);} else {alert(jsObject.msg);}"))
.give(TagContent::text, "Request notification permission");
In this code,
source.notifPerm
is assigned with permission value. When
action.perform();
is called the JavaScript in jsFilterFunctionBody is invoked to send
the value to the server. Eg 2: Suppose there is a button, let's say
btn1
it has an OnClick
event attribute.
This event attribute has ServerAsyncMethod
. When we click the button
it has to pop up some modal having some buttons. When we click the button on the modal it should invoke
the ServerAsyncMethod
of button btn1
.
How to achieve this?
In this case, the action
object
(from jsPreFunctionBody
of OnClick
of btn1
)
can be passed to the event attribute of button on the modal and
it can call perform()
function on that.
You should have some basic JavaScript knowledge to achieve this.
WffBMObject
WffBMObject
stores data as key value pairs. Unlike JSON, it can also contain
binary data (WffBMByteArray
) in its value. The data types supported by
WffBMObject
can be found in
BMValueType
enum.
WffBMObject
can also be used to send and receive binary data from server to
client and vice versa.
Check out this sample project for code reference.
CustomEventAttribute
com.webfirmframework.wffweb.tag.html.attribute.event.CustomEventAttribute
can be used to create a custom event attribute. See the below
sample code
CustomEventAttribute customEventAttribute = new CustomEventAttribute("onclick"
, jsPreFunctionBody, serverAsyncMethod, jsFilterFunctionBody, jsPostFunctionBody);