Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

XCO-JS: A Data Based JS Framework

DZone's Guide to

XCO-JS: A Data Based JS Framework

In this article, we explore various ways to use HTML, XML, and JavaScript to manipulate data using this cool data-based JavaScript framework.

· Web Dev Zone
Free Resource

Tips, tricks and tools for creating your own data-driven app, brought to you in partnership with Qlik.

XCO-JS is a comprehensive JS framework based on XCO data objects, including data encapsulation, data requests, template rendering, data binding, and data validation.

XCO-JS

Source Address: https://github.com/xsonorg/xco-js

Official website: http://xson.org/

1. XCO JavaScript Implementation Version

XCO, common object JavaScript implementation version, provides the XCO object based on the JS language feature's API. On XCO, common object data model can refer to https://dzone.com/articles/introduction-to-the-xco

1.1. Supported data types

The type of java The type of JS Type tag
int Number I
long Number L
float Number F
double Number D
char String C
boolean Boolean O
String String S
java.util.Date Date A
java.sql.Date Date E
java.sql.Time Date G
XCO XCO X
String[] Array SA
List<String> Array SL
Set<String> Array SS
XCO[] Array XA
List<XCO> Array XL
Set<XCO> Array XS
int[] Array IA
long[] Array LA
float[] Array FA
double[] Array DA

1.2. Use Examples

a. Set value

var xco = new XCO();

// Set the base type
xco.setIntegerValue("intVal", 2);
xco.setLongValue("longVal", 100001);
xco.setFloatValue("floatVal", 2.0);
xco.setDoubleValue("doubleVal", -0.3);
xco.setStringValue("stringVal", "hello xco.");

// Set the array
xco.setStringArrayValue("stringArray", ["aa", "bb", "cc"]);
xco.setIntegerArrayValue("intArray", [1, 3, 5, 8]);

// Set the XCO
var xco1 = new XCO();
xco1.setStringValue("stringVal", "china");
xco.setXCOValue("xcoVal", xco1);

After the above operation, the xco object in the example is represented in XML as follows.

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <I K="intVal" V="2"/>
    <L K="longVal" V="100001"/>
    <F K="floatVal" V="2"/>
    <D K="doubleVal" V="-0.3"/>
    <S K="stringVal" V="hello xco."/>
    <SA K="stringArray">
        <S V="aa"/>
        <S V="bb"/>
        <S V="cc"/>
    </SA>
    <IA K="intArray" V="1,3,5,8"/>
    <X K="xcoVal">
        <S K="stringVal" V="china"/>
    </X>
</X>

b. Taking Value

var intVal = xco.getIntegerValue("intVal");                 //number
var stringVal = xco.getStringValue("stringVal");            //string
var xcoVal = xco.getXCOValue("xcoVal");                     //XCO
var stringArray = xco.getStringArrayValue("stringArray");   //[]

// ... For more details please refer to xco.js

c. Serialization

// XML serialization
var xml = xco.toXML();

// Deserialization
var xco = new XCO();
xco.fromXML(xml);

d. Visited by ognl

xco.get('intVal');
xco.get('xcoVal.stringVal');
xco.get('stringArray[0]');

2. XCO Request

XCO requests are AJAX-based asynchronous requests, and the difference between ordinary AJAX requests is:

  1. contentType is application/xco;charset=utf-8.
  2. The request is POST.
  3. Request parameter is located in the BODY. The data format is an XML string that is serialized by the XCO object.

xco.jquery-{version}.js provides the concrete implementation of the XCO request. From the name, we see that the XCO request is dependent on jQuery. So when using XCO requests, we also need to introduce a JQuery class library.

2.1. Use Examples

<button type="button" name="t1" onclick="doSubmit()">XCO request</button>

<script type="text/javascript" src="/js/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="/js/xco-1.0.1.js"></script>
<script type="text/javascript" src="/js/xco.jquery-1.0.1.js"></script>
<script type="text/javascript">
    function doSubmit() {
        var xco = new XCO();
        xco.setIntegerValue("id", 1);
        xco.setStringValue("name", "david");
        var options = {
            url : "/m1.xco",        //The requested URL address
            data : xco,             //The requested parameter must be an XCO object
            success : doCallBack    //Successful callback function
        };
        $.doXcoRequest(options);
    }
    function doCallBack(data) {
        // data is the XCO object
        alert('doCallBack:\n' + data);
    }
</script>

Note: The server side of the receiving and processing, related to tangyuan-web components, will be in other articles in order to give a more a detailed introduction.

2.2. Successful Processing

For processing after the request is successful, the XCO request also provides support for multiple callback functions.

function doSubmit() {
    var xco = new XCO();
    xco.setIntegerValue("id", 1);
    xco.setStringValue("name", "david");
    var options = {
        url : "/m1.xco",        //The requested URL address
        data : xco,             //The requested parameter must be an XCO object
        success : [ doCallBack1, doCallBack2, doCallBack3 ]
    };
    $.doXcoRequest(options);
}

function doCallBack1(data) {
    // TODO
}
function doCallBack2(data) {
    // TODO
}
function doCallBack3(data) {
    // TODO
}

2.3. Result Detection

XCO requests to return the result is an XCO object we can get through the XCO object getCode method to get the status code (in general, 0 on behalf of the successful processing, non-0 on behalf of the failure), getMessage method to get the wrong message. For the return of the results, we tend to first check the status code, and then do business processing. Let's look at an example:

Example 1

function doCallBack(data) {
    if(1 == data.getCode()){
        alert(data.getMessage());
        // Processing error code 1
        return;
    }
    if(2 == data.getCode()){
        alert(data.getMessage());
        // Processing error code 2
        return;
    }
    ...
    if(0 == data.getCode()){
        // Processing normal business
    }
}

Now, we can use another way to achieve the above functions:

Example 2

function doSubmit() {
    var xco = new XCO();
    xco.setIntegerValue("id", 1);
    xco.setStringValue("name", "david");
    var options = {
        url : "/m1.xco",        //The requested URL address
        data : xco,             //The requested parameter must be an XCO object
        success : doCallBack,   //Successful callback function
        detector : doDetector   //Result detection: the function only returns true, then the successful callback will be executed
    };
    $.doXcoRequest(options);
}

function doDetector(data) {
    if(0 == data.getCode()){
        return true;
    }
    if(1 == data.getCode()){
        alert(data.getMessage());
        // Processing error code 1
    } else if(2 == data.getCode()){
        alert(data.getMessage());
        // Processing error code 2
    }
    return false;
}

function doCallBack(data) {
    // Processing normal business
}

Example 3

function doSubmit() {
    var xco = new XCO();
    xco.setIntegerValue("id", 1);
    xco.setStringValue("name", "david");
    var options = {
        url : "/m1.xco",        //The requested URL address
        data : xco,             //The requested parameter must be an XCO object
        success : doCallBack,   //Successful callback function
        detector : [doDetector1, doDetector2]
    };
    $.doXcoRequest(options);
}
function doDetector1(data) {
    if(1 == data.getCode()){
        alert(data.getMessage());
        // Processing error code 1
        return false;
    } 
    return true;
}
function doDetector2(data) {
    if(2 == data.getCode()){
        alert(data.getMessage());
        // Processing error code 2
        return false;
    } 
    return true;
}

In Example 3, we used two result detection functions. Only if the two detection functions return true, will the successful callback be executed, and if any one of the detection functions return false, it will end the callback process.

If we want to first detect whether the code is 0, if 0, follow-up is no longer need to do testing,  how to do it?  Can we change the code in Example 3 as follows :

function doDetector1(data) {
    if(0 == data.getCode()){
        return IGNORE_FOLLOW_UP;    //Returns a special marker, ignoring subsequent result detection.
    }
    // Other results detected
}

3. Template engine

The template engine is based on a predefined template, using padding data (XCO objects) for data padding, resulting in rendered HTML code.

XCO template engine features:

  1. HTML code and JS code separation.
  2. Keep the original HTML code and structure.
  3. To further improve the coding efficiency.

3.1. Use Examples

Template example

<div id="container"><!-- 
    <p>User ID: #{id}</p>
    <p>User Name: #{name}</p>
 --></div>

Code example

<script type="text/javascript" src="/js/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="/js/xco-1.0.1.js"></script>
<script type="text/javascript" src="/js/xco.jquery-1.0.2.js"></script>
<script type="text/javascript" src="/js/xco.variable-1.0.1.js"></script>
<script type="text/javascript" src="/js/xco.template-1.0.1.js"></script>
<script type="text/javascript">
    XCOTemplate.pretreatment('container');                      // Template preprocessing

    function doSubmit() {
        var xco = new XCO();
        // Set the value of the request parameter
        var options = {
            url : "/m1.xco",
            data : xco,
            success : doCallBack
        };
        $.doXcoRequest(options);
    }
    function doCallBack(data) {
        var html = XCOTemplate.execute("container", data);      // Fill the template, data is the XCO object
        document.getElementById("container").innerHTML = html;  // Render page
    }
</script>

Note: The data parameter in the doCallBack method is an XCO object after the XCO request is returned. In XML format it looks as follows:

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <I K="id" V="1001"/>
    <S K="name" V="xsonorg"/>
</X>

Rendered HTML

<div id="container">
    <p>User ID: 1001</p>
    <p>User Name: xsonorg</p>
</div>

Class Library Description

  1. xco.variable-1.0.1.jsTag parsing class library
  2. xco.template-1.0.1.jsTemplate Engine Class Library

3.2. Template Definition and Use

How do I define a template? The previous example has given the answer, and we define the template through the annotation label <! --...--> in HTML. Note: a template must have a container of their own, or how do we find him? In the template, we can set some tag, then we fill in the template; these tags will be replaced with the contents we want.

There are two types of tags in the template, one is the variable substitution tag, and the other is the function substitution tag.

3.2.1 Variable Substitution

Variable substitution refers to replacing the tag with the contents of the variable. The tag format for the variable substitution is #{xxx}, where # indicates that the tag is a variable substitution tag and xxx is the variable name.

3.2.1.1 The Default Value for Variable Substitution

#{xxx|yyy} represents a variable replacement tag with default values. Where: xxx is the variable name, | indicates that the subsequent yyy is the default. When the value corresponding to the variable xxx does not exist in the padding data, it will be replaced with this default value.

Template Example

<div id="container"><!-- 
    <p>#{x|123}</p>
    <p>#{y|'xsonorg'}</p>
 --></div>

Padding Data

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <I K="x" V="1001"/>
</X>

Rendered HTML

<div id="container">
    <p>1001</p>
    <p>xsonorg</p>
</div>

Description

If the template padding data exists x, then take the value of x to replace it, otherwise use the default value 123 to replace it. If the template padding data exists as y, then take the value of y to replace it, otherwise use the default value xsonorg to replace.

3.2.1.2 The Expression for Variable Substitution

In the variable substitution tag, an operation expression is allowed to exist. The template engine takes the result of the expression operation as an alternative.

Template Example

<div id="container"><!-- 
    <p>#{x+y}</p>
    <p>#{x*y}</p>
    <p>#{x+y*z}</p>
    <p>#{money + '$'}</p>
 --></div>

Padding Data

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <I K="x" V="1"/>
    <I K="y" V="2"/>
    <I K="z" V="3"/>
    <D K="money" V="1558.3"/>
</X>

Rendered HTML

<div id="container">
    <p>3</p>
    <p>2</p>
    <p>7</p>
    <p>1558.3$</p>
</div>

Description

Currently supported operators include: +-*/(). If the variables in the variable substitution tag are of type Number, the expression is an arithmetic expression, and the result after the operation is Number. If the variable has a String type, the expression represents a string concatenation, and the result after the operation is String.

3.2.1.3 The Function Call for Variable Substitution

#{xxx@yyy} represents a variable substitution tag with a function call, where xxx is the variable name, and @ indicates that the subsequent yyy is the called function.

In the template engine for this tag, the processing flow is as follows:

  1. Get the value corresponding to the variable xxx, assuming R1
  2. R1 is used as the yyy parameter, the yyy function is executed, the result of the return is assumed to be R2
  3. Replace this tag with R2

Template Example

<div id="container"><!-- 
    <p>#{create_time@formatDateTime}</p>
 --></div>

Padding Data

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <A K="create_time" V="2016-08-03 19:27:06"/>
</X>

Related Functions

function formatDateTime(_date) {
    return this.format(date, "yyyy-MM-dd");     // Format time
}

Rendered HTML

<div id="container">
    <p>2016-08-03</p>
</div>

Description

In this way, the general application scenario is to do the secondary processing for the values in the returned result. For example, the create_time in the previous example needs to be formatted before being replaced.

3.2.2 Function Substitution

The function substitution is the return value of a function as a replacement. The tag format for the function substitution is @{xxx}, where @ indicates that the tag is a function substitution tag and xxx is the function name.

Template Example

<div id="container"><!-- 
    <p>@{getOrderOp}</p>
 --></div>

Padding Data

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <L K="order_id" V="10001"/>
    <I K="order_state" V="1"/>
</X>

Code Example

function doCallBack(data) {
    var ext = {                                                 // Function container object
        getOrderOp : function(xco) {                            // The function used in the tag
            if(1 == xco.get('order_state')){
                return '<a href="###" onclick="pay(' + xco.get('order_id') + ')">Pay</a>';
            } else if(2 == xco.get('order_state')){
                return '<a href="###" onclick="confirmReceipt(' + xco.get('order_id') + ')">Confirm receipt</a>';
            } else {
                return '<a href="/order_detail.jsp?order_id=' + xco.get('order_id') + '">See details</a>';
            }
        }
    }
    var html = XCOTemplate.execute("container", data, ext);     // Fill the template, data is the XCO object
    document.getElementById("container").innerHTML = html;      // Render page
}

Rendered HTML

<div id="container">
    <p><a href="###" onclick="pay(10001)">pay</a></p>
</div>

Description

In the use of function substitution, the need to transfer an additional ext object, the object contains the required function. The parameter xco of functiongetOrderOp is the incoming parameter data (XCO object) when the XCOTemplate.execute method is executed.

The difference between function substitution and the function call for variable substitution.

  1. The parameters of function substitution are the entire padding data object, the parameters of the function call for variable substitution is a value in the padding data.
  2. The function call for variable substitution is generally used for secondary processing of data, and function substitution is generally used as a more complex HTML code to construct.

3.2.3 List Rendering

For page rendering using templates, the most common scenario is the list rendering.

Template Example

<table>
    <thead>
        <tr>
            <th>User ID</th>
            <th>User Name</th>
        </tr>
        <tbody id="users"><!-- 
            <tr>
                <td>#{users[i].user_id}</td>
                <td>#{users[i].user_name}</td>
            </tr>
         --></tbody>    
    </thead>
</table>

Padding Data

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <XL K="users">
        <X>
            <L K="user_id" V="101"/>
            <S K="user_name" V="Sykes"/>
        </X>
        <X>
            <L K="user_id" V="102"/>
            <S K="user_name" V="Grant"/>
        </X>
        <X>
            <L K="user_id" V="103"/>
            <S K="user_name" V="Fabian"/>
        </X>
        <X>
            <L K="user_id" V="104"/>
            <S K="user_name" V="Nadine"/>
        </X>
    </XL>
    <I K="$$CODE" V="0"/>
</X>

Code Example

function doCallBack(data) {
    var dataList = data.getXCOListValue("users");
    var html = '';
    for (var i = 0; i < dataList.length; i++) {
        data.setIntegerValue("i", i);
        html += XCOTemplate.execute("users", data);
    }
    document.getElementById("users").innerHTML = html;      
}

Rendered HTML

<table>
    <thead>
        <tr>
            <th>User ID</th>
            <th>User Name</th>
        </tr>
        <tbody id="users">
            <tr>
                <td>101</td>
                <td>Sykes</td>
            </tr>
            <tr>
                <td>102</td>
                <td>Grant</td>
            </tr>
            <tr>
                <td>103</td>
                <td>Fabian</td>
            </tr>
            <tr>
                <td>104</td>
                <td>Nadine</td>
            </tr>
        </tbody>            
    </thead>
</table>

4. Data Binding

Data binding is done using padding data (XCO objects), substituting binding tags, and page rendering.

4.1. Use Example

Set the binding tag

<div>
    <p id="p1">User ID:#{id}</p>
    <p id="p2">Nick name:#{name|'anonymity'}</p>
    <p id="p3">Age level:#{age@getAgeLevel}</p>
    <p id="p4">Create time:#{create_time@formatDateTime}</p>
    <p class="c2">@{getState}</p>
</div>

XCO Requests the returned padding data

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <L K="id" V="185"/>
    <S K="name" V="xsonorg"/>
    <I K="age" V="18"/>
    <I K="state" V="1"/>
    <A K="create_time" V="2017-08-05 15:23:58"/>
    <I K="$$CODE" V="0"/>
</X>

Code Example

<script type="text/javascript" src="/js/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="/js/xco-1.0.1.js"></script>
<script type="text/javascript" src="/js/xco.jquery-1.0.1.js"></script>
<script type="text/javascript" src="/js/xco.variable-1.0.1.js"></script>
<script type="text/javascript" src="/js/xco.databinding-1.0.1.js"></script>
<script type="text/javascript">
    var bindConfig = [ '#p1', '#p2', '#p3', '#p4', '.c2' ];     // Declare the binding tag container
    XCODataBind.pretreatment(bindConfig);                       // Preprocess the binding tag
    function doBind() {
        var xco = new XCO();
        XCODataBind.bind({                                      // Data binding
            url : "/m3.xco",                                    // XCO request URL
            extendedFunction : {                                // Function container object
                getState : function(xco){                       // The required function
                    if(1 == xco.get('state')){
                        return '<b>verified</b>';
                    } else {
                        return '<a href="/toCertify.jsp?id=' + xco.get('id') + '">toCertify</a>';
                    }
                }
            }
        });
    }
    function getAgeLevel(age){                                  // Related functions
        if(age < 20){
            return 'youth';
        }           
        return 'middle aged';
    }
</script>

Rendered HTML

<div>
    <p id="p1">User ID:185</p>
    <p id="p2">Nick name:xsonorg</p>
    <p id="p3">Age level:youth</p>
    <p id="p4">Create time:2017-08-05 15:30:59</p>
    <p class="c2"><b>verified</b></p>
</div>

Class Library Description

  1. xco.variable-1.0.1.jsTag parsing class library
  2. xco.databinding-1.0.1.jsData binding class library

4.2. Declare the Binding Tag Container

When using data binding, you need to declare the binding tag container, such as:

var bindConfig = [ '#p1', '#p2', '#p3', '#p4', '.c2' ];     // Declare the binding tag container

Where #p1 represents the HTML element with the ID of p1.c2 identifies the HTML element with a CLASS of c2. In data binding, the search for HTML elements is based on jQuery, so the specific lookup expression can be found in the jQuery selector.

4.3. Variable Tags and Function Tags

The tags in the data binding also support variable tags and function tags, specifically referring to the contents of the template engine section.

4.4. Attribute Binding

Data binding can not only bind the contents of HTML, the same can be bound HTML element attributes.

Set the Binding Tag

<a id="p5" href="toCertify.jsp?id=#{id}">#{name}</a>

Padding Data

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <L K="id" V="185"/>
    <S K="name" V="xsonorg"/>
</X>

Code Example

var bindConfig = [ {el : '#p5', attr: ['href', 'html']} ];  // Declare the binding tag container
XCODataBind.pretreatment(bindConfig);                       // Preprocess the binding tag

var xco = new XCO();
XCODataBind.bind({                                          // Data binding
    url : "/m3.xco",                                        // XCO request URL
});

Rendered HTML

<a id="p5" href="toCertify.jsp?id=185">xsonorg</a>

Description

Before we declare a binding tag container, we only need an ID or CLASS before we can, but why is it so complicated? In fact, the statement here is a complete statement for an HTML element, such as:

{el : '#p5', attr: ['href', 'html']}

Where el represents the query expression for the element and attr indicates that the binding tag is in those attributes of the element. Before the statement #p1, just a simplified way, its complete expression should be:

{el : '#p1', attr: 'html'}

4.5. Namespaces

In a page, suppose we need to show two parts of information, part of the user's basic information and part of the user's financial information, but the two parts of the data are obtained separately. Based on this scenario, data binding introduces the concept of namespace. The namespace is the collection of binding tags that match the padding data. Let's look at a complete example below.

Set the Binding Tag

<div>
    <p id="p1">User ID:#{id}</p>
    <p id="p2">Nick name:#{name|'anonymity'}</p>
    <p id="p3">Age level:#{age@getAgeLevel}</p>
    <p id="p4">Create time:#{create_time@formatDateTime}</p>
    <p class="c2">@{getState}</p>
    <a id="p5" href="toCertify.jsp?id=#{id}">#{name}</a>
</div>

<div>
    <p id="p6">Account credits:#{xx:score}</p>
    <p id="p7">Account funds:#{xx:(money/100)+'$'}</p>
</div>

Code Example

    var bindConfig = [ '#p1', '#p2', '#p3', '#p4', '.c2', {el : '#p5', attr: ['href', 'html']}, '#p6', '#p7'];
    XCODataBind.pretreatment(bindConfig);
    function doBind() {
        var xco = new XCO();
        XCODataBind.bind({                                      // Data binding
            url : "/m3.xco",                                    // XCO request URL
            extendedFunction : {                                // Function container object
                getState : function(xco){                       // The required function
                    if(1 == xco.get('state')){
                        return '<b>verified</b>';
                    } else {
                        return '<a href="/toCertify.jsp?id=' + xco.get('id') + '">toCertify</a>';
                    }
                }
            }
        });
        XCODataBind.bind({
            ns : 'xx',
            url : "/m4.xco"
        }); 
    }

XCO Requests the Returned Padding Data

/m3.xco request return result:

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <L K="id" V="185"/>
    <S K="name" V="xsonorg"/>
    <I K="age" V="18"/>
    <I K="state" V="1"/>
    <A K="create_time" V="2017-08-05 15:23:58"/>
    <I K="$$CODE" V="0"/>
</X>

/m4.xco request return result:

<?xml version="1.0" encoding="UTF-8"?>
<X>
    <L K="id" V="185"/>
    <L K="score" V="100"/>
    <L K="money" V="10000"/>
    <I K="$$CODE" V="0"/>
</X>

Rendered HTML

<div>
    <p id="p1">User ID:185</p>
    <p id="p2">Nick name:xsonorg</p>
    <p id="p3">Age level:youth</p>
    <p id="p4">Create time:2017-08-05 15:30:59</p>
    <p class="c2"><b>verified</b></p>
</div>

<div>
    <p id="p6">Account credits:100</p>
    <p id="p7">Account funds:100$</p>
</div>

Description

In the previous example, we set the namespace through ns:'xx' when we used bind. The namespace is used in the binding tag with #{xx:score}. In fact, the previous example also implies the existence of another namespace, an empty namespace, that is, the default namespace. When bind does not explicitly refer to ns, the default namespace will be used, and the default namespace will also be used in the binding tag that does not use the prefixxx explicitly.

Explore data-driven apps with less coding and query writing, brought to you in partnership with Qlik.

Topics:
xco ,js ,template ,databinding ,validation ,ajax

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}