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);