Tutorial # 4: HTML Tables

Table of contents

Tutorial # 4: HTML Tables
1: HTML to receive the table from the server
2: JS to send a request to the server
3: Perl Controller to respond to this request
4: Perl View to respond to this request
History
Links

Tutorial # 4: HTML Tables

1: HTML to receive the table from the server

        <div id="report_result"></div>

Notes:

# 1: The inclusion of CSS, JS, and DataTables stuff, is explained in tut # 1.

# 2: Actually, I like to center the output on the page, so I put this div inside a centered table, but that is not necessary for this tut.

2: JS to send a request to the server

        function generate_report()
        {
                $.ajax
                ({
                        data:
                        {
                                communication_type_id:     $("#report_communication_type_id").val(),
                                gender_id:                 $("#report_gender_id").val(),
                                ignore_communication_type: $("#ignore_communication_type").val(),
                                ignore_gender:             $("#ignore_gender").val(),
                                ignore_role:               $("#ignore_role").val(),
                                ignore_visibility:         $("#ignore_visibility").val(),
                                report_entity_id:          $("#report_entity_id").val(),
                                report_id:                 $("#report_id").val(),
                                role_id:                   $("#report_role_id").val(),
                                sid:                       $("#report_sid").val(),
                                visibility_id:             $("#report_visibility_id").val()
                        },
                        dataType: "xml",
                        type: "POST",
                        url: "/Report/display",
                        success: function(response, status, jqXHR)
                        {
                                var $xml  = $(response);
                                var error = $xml.find("error").text();
                                var html  = $xml.find("html").text();

                                if (error != "")
                                {
                                        status_error(error, html);

                                        return;
                                }

                                status_ok();

                                $("#report_result")
                                .empty()
                                .append(html);
                        },
                        error: function(jqXHR, status, error)
                        {
                                status_error("Cannot generate report", "HTTP error: " + error);
                        }
                });
        }

Notes:

# 1: $("#sid").val() is jQuery's syntax for getting the value of a CGI form field. This code moves these values into a data structure which is sent to the server.

# 2: The syntax '<: $x :>' is a placeholder used by Text::Xslate.

# 3: This code is all taken from App::Office::Contacts V 2.00, which I'm afraid is not yet released.

# 4: The controller called (on the server when this request is submitted) is Report (from /Report above). Since I'm running this as a plack script via CGI::Snapp::Dispatch, and the latter is initialized with:

        prefix => 'App::Office::Contacts::Controller'

then the code actually run is the display() method (from /display above) in the module App::Office::Contacts::Controller::Report. The Perl code follows.

# 5: In this code, I'm not processing the result from the server. I'm just jamming it into a div, using append(html). If you want more sophisticated processing, consider using taconite, which allows you to send a structured response from the server, with taconite unpacking it for you in the JS.

3: Perl Controller to respond to this request

        sub display
        {
                my($self) = @_;

                $self -> log(debug => "Controller::Exporter::Report.display()");

                $self -> param('db') -> simple -> begin_work;
                $self -> add_header('-Status' => 200, '-Content-Type' => 'text/xml; charset=utf-8');

                my($response, $result);

                try
                {
                        $result = App::Office::Contacts::Util::Validator -> new
                        (
                                app    => $self,
                                config => $self -> param('config'),
                                db     => $self -> param('db'),
                                query  => $self -> query,
                        ) -> report;

                        if ($result -> success)
                        {
                                $response = $self -> param('db') -> library -> build_ok_xml
                                        (
                                                $self -> param('view') -> report -> generate_report($result)
                                        );
                        }
                        else
                        {
                                $response = $self -> param('db') -> library -> build_error_xml
                                (
                                        'Cannot generate report',
                                        $result,
                                );
                        }

                        $self -> param('db') -> simple -> commit;
                }
                catch
                {
                        my($error) = $_;

                        $self -> param('db') -> simple -> rollback;

                        # Try to log the error despite the error.

                        $self -> log(error => "System error: $error");

                        $response = $self -> param('system_error');
                };

                return encode('utf8', $response);

        } # End of display.

4: Perl View to respond to this request

Step 1: Actually, generate_report(\$input) does a lot of work, but basically it generates a Perl array, which is what we want to return to the client. So here I just assume an array is available, and at the end of generate_report(\$input) just call:

        return $self -> format_record_report([@item]);

Step 2: So, what does the formatter actually do?

        sub format_record_report
        {
                my($self, $result) = @_;

                $self -> db -> logger -> log(debug => 'View::Role::Report.format_record_report(...)');

                my($html) = <<EOS;
        <table class="display" id="result_table" cellpadding="0" cellspacing="0" border="0" width="100%">
        <thead>
        <tr>
                <th>Count</th>
                <th>Name</th>
                <th>Entity type</th>
                <th>Contact via</th>
                <th>Role</th>
                <th>Visibility</th>
        </tr>
        </thead>
        <tbody>
        EOS

                my($count) = 0;

                my($class);

                for my $row (@$result)
                {
                        $class = (++$count % 2 == 1) ? 'odd gradeC' : 'even gradeC';
                        $html  .= <<EOS;
        <tr class="$class">
                <td>$count</td>
                <td>$$row{data}{name}</td>
                <td>$$row{type}</td>
                <td>$$row{data}{communication_type_name}</td>
                <td>$$row{data}{role_name}</td>
                <td>$$row{data}{visibility_name}</td>
        </tr>
        EOS
                }

                $html .= <<EOS;
        </tbody>
        <tfoot>
        <tr>
                <th>Count</th>
                <th>Name</th>
                <th>Entity type</th>
                <th>Contact via</th>
                <th>Role</th>
                <th>Visibility</th>
        </tr>
        </tfoot>
        </table>
        EOS

                return $html;

        } # End of format_record_report.

Notes:

There's a lot happening here, so we'll step thru it bit by bit.

# 1: We start with 2 divs, who's ids are mandatory. DataTables will search the HTML for these, to know what table to process within the stuff sent by the server.

# 2: The attributes on \<table ...> are mandatory. Again, just let DataTables do the work.

# 3: The \<thead> is mandatory. Again, it's what DataTables uses to find the columns in the table.

# 4: Likewise, \<tfoot>.

# 5: The loop in the middle, 'for my $row (@$result)', is the mechanism used to determine the various classes representing the colours desired. I just use 2 colours here.

# 6: This loop is where any sort of processing can take place. Here's some utf8 stuff from the Search controller.

        ...
        $class    = (++$count % 2 == 1) ? 'odd gradeC' : 'even gradeC';
        $name     = encode('utf8', $$row{name});
        $surname  = encode('utf8', $$row{surname} || '-');
        $html     .= <<EOS;
        ...

It all depends in what you want to do, and what type of data you're retrieving from your database.

# 7: We just return the resultant HTML to the client, with 'return $html;'.

What's so impressive is that after that, jQuery and DataTables take over. This contrasts almost shockingly with the massive overhead required by us as programmers when using YUI, for instance.

I've written much more on this elsewhere.

The design of jQuery (at least in this respect) must humiliate the designers of YUI...

History

V 1.01 2013-07-01. Update after releasing App::Office::Contacts V 2.01.

V 1.00 2013-05-07. Original version.

Links

My home page

All tutorials (Includes references)

POD source for this tutorial