net

Authoring Components

Component GUI model

Bundling UI functionality in client-side components is a pretty obvious idea. The reference implementation of the component library uses just trivial stateless function maps, with the simple inheritance.

    jasty.Button = jasty.extend(jasty.Control, {

        init: function(self, opts) {
            self.text(opts.text);
            self.click(function() {
                jasty.raiseEvent(self, opts.onClick, {srcId: self.attr("id"),
                data: opts.data});
                return false;
            });
        },

        text: function(self, value) {
            self.text(value);
        }
    });

Method init is reserved for component initialization. I would generally recommend to put the whole rendering code for the component into this method. So that the only thing, rendered on the server is the outer tag with nothing but an id specified. The remaining initialization occurs in the init-method.

    <button id="someId"></button>
    <script>
        jasty.Button.init($("#someId"), {
            text: "initial text",
            onClick: "buttonClicked"})
    </script>

Behavioural methods may substantially depend on the DOM-representation of the component. That's why it's reasonable to keep everything in one place - in the component code - only having a single DOM-tag to be rendered by the server.

To facilitate calling methods on complex selectors, as well as to provide a common interface to various component writing styles, dispatching plugin may be used:

    $("#someId").jasty("Button", "text", ["some text"])

This jQuery-plugin resolves the component and calls the specified method sequentially for every selected element, applying parameters from the array in the 3rd parameter.

For the components designed in a different way, alternative dispatching plugins might be necessary. But the calling interface should be kept the same:


$(<selector>).<dispatcher>(<component>, <method>, <parameters array>)

Sticking to the common interface for call dispatchers allows for easy code generation by the server-side component proxies.

Server-side proxy components

Proxy components are used to enable interaction with the client components from the server-side code.

    public class Button extends Component {

        @InitProperty
        private String text;
        @InitProperty
        private String onClick;

        public void setText(String text) {
            this.text = text;
            invoke("text", text);
        }

        @Override
        public String getHtmlTag() {
            return "button";
        }
    }

By calling invoke method, component method (setText) generates javascript code, which is then included in the AJAX-response and executed in the browser.

For example, these calls

    Button btn = new Button();
    btn.setId("someId");
    btn.setText("new text");

produce following script:

    $("#someId").jasty("Button", "text", ["new text"])

Emitting executable javascript is the only method of AJAX-response in the framework, and it perfectly covers all needs.

The proxy components are actively used in the event handlers of the Forms.