Skip to content

Control Template

Communication

The cSpinner control includes all the components that make up the control (DataFlex class, JavaScript class, CSS, and include changes for index.html). There is also an example of how to use it in a Web application.

cSpinner.pkg

Use cWebBaseControl.pkg

Class cSpinner is a cWebBaseControl

    Procedure Construct_Object
        Forward Send Construct_Object
        // Define web properties
        { WebProperty=True }
        Property Integer piSpinValue 0

        // OnDecrement event properties
        { WebProperty=True }
        Property Boolean pbServerOnDecrement True
        { WebProperty=True }
        Property String psClientOnDecrement ""

        // OnIncrement event properties
        { WebProperty=True }
        Property Boolean pbServerOnIncrement True
        { WebProperty=True }
        Property String psClientOnIncrement ""

        // Set client-side class
        Set psJSClass to "Spinner"
    End_Procedure

    { MethodType=Event }
    Procedure OnDecrement Integer iNewValue Integer iOldValue
        // Empty event stub
    End_Procedure

    { MethodType=Event }
    Procedure OnIncrement Integer iNewValue Integer iPrevValue
        // Empty event stub
    End_Procedure

    Procedure End_Construct_Object
        Forward Send End_Construct_Object
        // Publish functions called from the client
        WebPublishProcedure OnDecrement
        WebPublishProcedure OnIncrement
    End_Procedure

End_Class

Spinner.js

This file needs to be placed inside the AppHTML folder and included from the HTML file (index.html).

/*
The constructor method defines properties and events. The 'prop' function is used to define web
properties. The 'event' function defines events. Private properties usually start with a '_'.
@param  sName       The object name as a string.
@param  oParent     Reference to the parent object.
*/
self.Spinner = class Spinner extends df.WebBaseControl {
    constructor(sName, oParent) {
        // Forward Send
        super(sName, oParent);
        /*
        Types can be: df.tString, df.tInt, df.tNumber, df.tDate, df.tBool
        */
        this.prop(df.tInt, "piSpinValue", 1);
        /*
        Types can be: df.cCallModeDefault, df.cCallModeWait, df.cCallModeProgress
        */
        this.event("OnDecrement", df.cCallModeWait);
        this.event("OnIncrement", df.cCallModeWait);
        // Private properties
        this._eBtnDecr = null;
        this._eBtnIncr = null;
        // Determine CSS classname for outermost div
        this._sControlClass = "Spinner";
    }

    /*
    The openHtml method is called by the render method to generate the opening HTML. In a lot of cases
    you would open HTML elements. The HTML generation is split up into an openHtml and a closeHtml
    method to provide more flexibility during inheritance. The aHtml parameter passed is an array that
    is used as a string builder. HTML code can be added using the push method.
    @param  aHtml   String builder array to be filled with HTML.
    */
    openHtml(aHtml) {
        // Forward Send (before so base class can add wrapping elements)
        super.openHtml(aHtml);
        aHtml.push('<div class="Spinner"></div>');
    }

    /*
    The closeHtml method is called by the render method to generate the closing HTML. In most cases you
    would close the HTML element here.
    @param  aHtml   String builder array to be filled with HTML.
    */
    closeHtml(aHtml) {
        // Forward Send (after so base class can add wrapping elements)
        super.closeHtml(aHtml);
    }

    /*
    The afterRender method is called by the render method after the HTML is parsed by the browser. It
    gives a chance to get references to the DOM elements and to do first manipulation. This is also the
    place where you would attach event listeners. It is common practice to manually execute some of the
    setter methods here to do further initialization.
    */
    afterRender() {
        // Get references to DOM elements
        this._eBtnDecr = df.dom.query(this._eElem, "button.SpinDecr");
        this._eBtnIncr = df.dom.query(this._eElem, "button.SpinIncr");
        this._eControl = df.dom.query(this._eElem, "span.SpinVal");
        // Forward Send
        super.afterRender();
        // Attach DOM event listeners
        df.events.addDomListener("click", this._eBtnDecr, this.onDecrClick, this);
        df.events.addDomListener("click", this._eBtnIncr, this.onIncrClick, this);
        // Execute setters to finish initialization
        this.set_piSpinValue(this.piSpinValue);
    }

    /*
    This is a setter method for the psCaption property. It is called by the framework whenever the value
    for psCaption changes (WebSet psCaption of oObject) passing the new value. We update the user
    interface by changing a DOM element. Note that we first check if we already have a handle to the DOM
    element.
    @param  iVal   The new value.
    */
    set_piSpinValue(iVal) {
        if (this._eControl) {
            df.dom.setText(this._eControl, iVal);
        }
    }

    /*
    This method handles an event from the DOM. It gets the oEvent object from the framework providing
    information about the event. The framework has its own abstract layer on top of the browsers event
    system to smoothen out the differences between browsers.
    @param oEvent   The event object that is provided by the framework.
    */
    onDecrClick(oEvent) {
        const iPrevValue = this.piSpinValue;
        this.set("piSpinValue", (iPrevValue - 1));
        // Fire an event on the server
        this.fire("OnDecrement", [this.piSpinValue, iPrevValue], function() {
            // This code is executed after the server processed this event
        });
    }

    /*
    This method handles an event from the DOM. It gets the oEvent object from the framework providing
    information about the event. The framework has its own abstract layer on top of the browsers event
    system to smoothen out the differences between browsers.
    @param oEvent   The event object that is provided by the framework.
    */
    onIncrClick(oEvent) {
        const iPrevValue = this.piSpinValue;
        this.set("piSpinValue", (iPrevValue + 1));
        // Fire an event on the server
        this.fire("OnIncrement", [this.piSpinValue, iPrevValue], function() {
            // This code is executed after the server processed this event
        });
    }
}

Spinner.css

This file needs to be placed inside the AppHTML folder and included from the HTML file (index.html).

/* Define default style */
.Spinner button {
    width: 20px;
}

.Spinner .SpinVal {
    padding: 4px;
    font-weight: bold;
}

/* Define theme customizations */
.Df_Modern_Sky .Spinner button {
    background-color: #313F54;
    color: #FFFFFF;
}

.Df_Web_Creme .Spinner button {
    background-color: #F2F3F5;
    border: 1px solid #CCCCCC;
    border-radius: 4px;
}

Index.html Changes

Two lines are added to the index.html below the comment to include controls into the page. This makes them usable within the application.

Using the Control

The example below shows how the control can be used. The class needs to be included and then it can be used as any other control. The previewer will show a dotted line where the control is supposed to go, so if implemented correctly, it should be in that position when running the application.

Use cSpinner.pkg

Object oSpinner1 is a cSpinner
    Set psLabel to "Spinner"
    Set piColumnSpan to 8
    Set pbServerOnIncrement to True

    Procedure OnIncrement Integer iNewValue Integer iPrevValue
        Forward Send OnIncrement iNewValue iPrevValue
        Send ShowInfoBox("Incremented to: " + String(iNewValue))
    End_Procedure
End_Object

Previous Topic: Communication

See Also

Developing Web Applications