[201611][DatTX] Create Print page by Jqurery Template, Ajax in Webform asp.net

Hello mọi người.

Tháng 11 này mình sẽ viết bài về các tạo 1 trang print sử dụng Ajax, Jquery Template.

Chúng ta sẽ bắt tay vào thực hiện chủ đề nhé.

Mục tiêu của bài viết hôm này là tập trung hướng dẫn:

  1. tạo sẵn 1 template kiểu html
  2. sử dụng Ajax để request server lấy dữ liệu
  3. sử dụng Jquery template để binding vào template
  4. bung popup print result

Trước khi đi vào bài thì các bạn cần phải hiểu Jquery template là cái gì và nó hoạt động ra sao mình xin giới thiệu link để tìm hiểu về JQuery Template

Để minh họa cho ví dụ thì mình xin lấy data của bài hôm trước

  public class OrdersViewModel
    {
        public int Id { get; set; }

        public int CustomerId { get; set; }

        public DateTime OrderDate { get; set; }

        public string Status { get; set; }

        public string CustomerName { get; set; }

        public string CountryName { get; set; }

        public decimal TotalPay { get; set; }

        public int TotalQuantity { get; set; }

        public List<OrderDetailsViewModel> ListOrder { get; set; }

        public CustomerInforViewModel CustomerInfor { get; set; }

        public OrdersViewModel()
        {
            ListOrder = new List<OrderDetailsViewModel>();
            CustomerInfor = new CustomerInforViewModel();
        }
    }

 public class OrderDetailsViewModel
    {
        public int Id { get; set; }

        public int OrderId { get; set; }

        public int ProductId { get; set; }

        public decimal UnitPrice { get; set; }

        public decimal TotalPrice
        {
            get
            {
                return UnitPrice * Quantity;
            }
        }

        public int Quantity { get; set; }

        public string ProductName { get; set; }
    }

Ok bây giờ chúng ta sẽ đi vào bước đầu tiên là tạo template, file template là 1 html mà ở đó chúng ta sẽ chỉ cho Jquery biết là sẽ binding cái gì và ở đâu

  • Jquery sẽ dựa vào biểu tượng $ để tìm kiểm trong Json có property đó ko, nếu có sẽ bind data vào vị trí jquery đabg trỏ tới

<div class="container">

    <div class="row" style="text-align:center">
        <h1> Order ${Id}</h1>
    </div>
    <div class="row">
        <div class="col-lg-6 col-md-6" style="text-align:left">
            <span> Status: ${Status}</span>
        </div>
        <div class="col-lg-6 col-md-6" style="text-align:right">
            <span> Order Date:  ${OrderDate}</span>
        </div>
    </div>
    <br />
    <br />
    <div class="section-detail">
        <fieldset>
            <legend><span class="header-title">Order Detail</span></legend>
            <div class="row">
                <div class="col-lg-12">
                    <table class="table" id="tbl-product-order">

                        <thead>
                            <tr>
                                <th>
                                    #
                                </th>
                                <th>
                                    Product
                                </th>
                                <th>
                                    Qty
                                </th>
                                <th>
                                    Unit Price
                                </th>
                                <th>
                                    Total
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            {{each(i, orderDetail) ListOrder}}
                            <tr>
                                <td>@i</td>
                                <td>${orderDetail.ProductId}</td>
                                <td>${orderDetail.Quantity}</td>
                                <td><span>${orderDetail.UnitPrice}</span></td>
                                <td><span>${orderDetail.TotalPrice}</span></td>
                            </tr>
                            {{/each}}
                        </tbody>
                        <tfoot>
                            <tr>
                                <td></td>
                                <td>TOTAL</td>
                                <td><span>${TotalQuantity}</span></td>
                                <td></td>
                                <td><span>${TotalPay}</span></td>
                                <td></td>
                            </tr>
                        </tfoot>
                    </table>

                </div>
            </div>
        </fieldset>
    </div>
</div>

giờ chúng ta đã có template rồi việc tiếp theo chúng ta sẽ làm là những bước sau

  1. Load Template sẵn lên page bằng Javascript $(document).ready()
  $(document).ready(function () {
            loadTemplate();
        });

Vậy ở đây chúng ta load cái gì và ở đâu, mọi người đọc function "loadTemplate" sẽ hiểu ngày

  function loadTemplate() {
            var $templates = $('script[type="text/html"]');
            $templates.each(function () {
                if ($(this).attr("src")) {
                    $.ajax(
                      $(this).attr("src"),
                      {
                          async: false,
                          context: this,
                          success: function (data) { $(this).html(data); }
                      }
                    );
                }
            });
        }

Khi function loadTemplate được gọi nó sẽ quét qua page và tìm xem có có thông tin của template trong page hay ko, nếu có thì sẽ dùng Jquery load sẵn lên page khi nào cần dùng sẽ gọi template bằng Jquery như 1 element .

Code ở page như sau

<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
    <script type="text/javascript" src="<%= ResolveUrl("~/Scripts/jquery.tmpl.js")%>"></script>
    <script type="text/javascript">
              function loadTemplate() {
            var $templates = $('script[type="text/html"]');
            $templates.each(function () {
                if ($(this).attr("src")) {
                    $.ajax(
                      $(this).attr("src"),
                      {
                          async: false,
                          context: this,
                          success: function (data) { $(this).html(data); }
                      }
                    );
                }
            });
        }
        $(document).ready(function () {
            loadTemplate();
        });

        function printOrder() {
            var orderJson = {
                id: '1'
            };
            //in display.js
            printForm('発注書', '/Default.aspx/GetDataJson', orderJson, 'template_Order');
        }
    </script>
    <script id="template_Order" type="text/html" src="/Template/OrderTemplate.html"></script>
</asp:Content>

Ở đây các bạn thấy element

<script id="template_Order" type="text/html" src="/Template/OrderTemplate.html"></script>

Đây chính là nơi template sẽ được load lên.

Sau khi chúng ta đã có template thì công việc chúng ta là tạo button Print để gọi lên server lấy data và bind vào templete

        function printOrder() {
            var orderJson = {
                id: '1'
            };
            //in display.js
            printForm('発注書', '/Default.aspx/GetDataJson', orderJson, 'template_Order');
        }
function printForm(title, urlAjax, objInput, idTemplate) {
            $.ajax({
                type: 'POST',
                url: urlAjax,
                data: "{objInput:" + JSON.stringify(objInput) + "}",
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                success: function (response) {
                    var previewWnd = window.open("", title, 'scrollbars=no, width='500px', height='500px');
                    var htmlcontent = '<html></html>';
                    previewWnd.document.open();
                    previewWnd.document.write(htmlcontent);
                    previewWnd.document.close();
                    $("#" + idTemplate).tmpl(clientData).appendTo(previewWnd.document.body);
                    previewWnd.document.title = title;
                    setTimeout(function () {
                        previewWnd.document.close();
                        previewWnd.print();
                    }, 1000);

                },
                error: function (response) {
                    alert(response.responseJSON.Message);
                }
            });
        }

Code Behind

 [System.Web.Services.WebMethod()]
        public static OrdersViewModel GetDataJson(OrdersViewModel objInput)
        {
            OrdersViewModel model = new OrdersViewModel()
            {
                Id = 1,
                Status = "New",
                OrderDate = DateTime.Now,
                ListOrder = new List<OrderDetailsViewModel>()
            };

            model.ListOrder.Add(new OrderDetailsViewModel() { ProductId = 1, Quantity = 2, UnitPrice = 20 });
            model.ListOrder.Add(new OrderDetailsViewModel() { ProductId = 2, Quantity = 3, UnitPrice = 30 });
            model.ListOrder.Add(new OrderDetailsViewModel() { ProductId = 3, Quantity = 4, UnitPrice = 40 });
            model.ListOrder.Add(new OrderDetailsViewModel() { ProductId = 4, Quantity = 5, UnitPrice = 50 });
            model.ListOrder.Add(new OrderDetailsViewModel() { ProductId = 5, Quantity = 6, UnitPrice = 60 });

            return model;
        }

Mình giải thích function này như sau

  1. Ajax gọi server để lấy data dưới dạng Json
  2. Sau khi có được Json mình sẽ khởi tạo 1 popup với blank body
  3. Dùng jquery bind data vào template và append vào popup Body
  4. Cuối cùng gọi lệnh in cho popup

Như vậy cơ bản là đã xong, việc cuối cùng là tạo button Print và call function PrintOrder thôi

<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
    <script type="text/javascript" src="<%= ResolveUrl("~/Scripts/jquery.tmpl.js")%>"></script>
    <script type="text/javascript">
        function printForm(title, urlAjax, objInput, idTemplate) {
            $.ajax({
                type: 'POST',
                url: urlAjax,
                data: "{objInput:" + JSON.stringify(objInput) + "}",
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                success: function (response) {
                    var htmlcontent = '<html></html>';
                    previewWnd.document.open();
                    previewWnd.document.write(htmlcontent);
                    previewWnd.document.close();
                    $("#" + idTemplate).tmpl(clientData).appendTo(previewWnd.document.body);
                    previewWnd.document.title = title;
                    setTimeout(function () {
                        previewWnd.document.close();
                        previewWnd.print();
                    }, 1000);

                },
                error: function (response) {
                    alert(response.responseJSON.Message);
                }
            });
        }
        function loadTemplate() {
            var $templates = $('script[type="text/html"]');
            $templates.each(function () {
                if ($(this).attr("src")) {
                    $.ajax(
                      $(this).attr("src"),
                      {
                          async: false,
                          context: this,
                          success: function (data) { $(this).html(data); }
                      }
                    );
                }
            });
        }
        $(document).ready(function () {
            loadTemplate();
        });

        function printOrder() {
            var orderJson = {
                id: '1'
            };
            //in display.js
            printForm('発注書', '/Default.aspx/GetDataJson', orderJson, 'template_Order');
        }
    </script>
    <script id="template_Order" type="text/html" src="/Template/OrderTemplate.html"></script>

    <div class="row">
        <button type="button" onclick="printOrder(); return false;">Print</button>
    </div>

</asp:Content>

Nhưng đây chư phải là kết thúc, đoạn này chúng ta sẽ gặp rắc rối với Internet Exxplorer thần thánh, vì nó sẽ ko hiểu đc lệnh Append của Jquery

Chúng ta edit lại function PrintForm 1 xí

 function printForm(title, urlAjax, objInput, idTemplate) {
            $.ajax({
                type: 'POST',
                url: urlAjax,
                data: "{objInput:" + JSON.stringify(objInput) + "}",
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                success: function (response) {
                    var htmlcontent = '<html></html>';
                    previewWnd.document.open();
                    previewWnd.document.write(htmlcontent);
                    previewWnd.document.close();
                    previewWnd.document.title = title;
                      var ua = window.navigator.userAgent;
        var msie = ua.indexOf("MSIE ");
        var msieversion = msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)
                     if (msieversion) {
                           var head = '<?xml version="1.0" encoding="SHIFT_JIS" ?>' +
                            '<!DOCTYPE html >' + '<html lang="ja">' +
                            '<head><meta charset="shift_jis" /><meta http-equiv="Content-Style-Type" content="text/css" /><meta http-equiv="Content-Script-Type" content="text/javascript" /><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /><meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0" /></head>';
                var prtContent = head + '<body>' + $("#" + idTemplate).tmpl(clientData).html() + '</body></html>';
                previewWnd.document.write(prtContent);
                     } else {
                $("#" + idTemplate).tmpl(clientData).appendTo(previewWnd.document.body);
                    }
                    setTimeout(function () {
                        previewWnd.document.close();
                        previewWnd.print();
                    }, 1000);

                },
                error: function (response) {
                    alert(response.responseJSON.Message);
                }
            });
        }

Đối với IE thì mình ko dùng Append mà mình sẽ render ra code HTML rồi sau đó write vào body của popup ngoài ra có 1 note sau

  • Khi tạo file template thì ko đc sử thẻ <style> vì nó có thể gây làm chêt Jquery template
  • Print Popup sẽ ko ăn đc css của Parent page nên muốn có Print Page có css thì các bạn có thể tạo 1 file css rồi append theo vào cho popup

Đối với các trình duyệt khác IE

var css_base = $("<link></link>", {
                    rel: "stylesheet",
                    type: "text/css",
                    href: "/common/css/base.css"
                });
css_base.appendTo(previewWnd.document.head);

Còn đối với IE thì ta cộng chuỗi vào lúc tạo head cho page

      //previewWnd.document.head.append('<link rel="stylesheet" href="/common/css/layout.css" type="text/css" />');
                var head = '<?xml version="1.0" encoding="SHIFT_JIS" ?>' +
                            '<!DOCTYPE html >' + '<html lang="ja">' +
                            '<head><meta charset="shift_jis" /><meta http-equiv="Content-Style-Type" content="text/css" /><meta http-equiv="Content-Script-Type" content="text/javascript" /><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /><meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0" />' +
                            '<link href="/common/css/Base.css" rel="stylesheet" type="text/css" media="all" /><link href="/common/css/layout.css" rel="stylesheet" type="text/css" media="all" />' +

                            '</head>';
                var prtContent = head + '<body>' + $("#" + idTemplate).tmpl(clientData).html() + '</body></html>';
                previewWnd.document.write(prtContent);

Ngoài ra sẽ dính lỗi khi bung popup Print sẽ tạo 1 page blank ở cuối, để khắc phục điều này trong file css bạn define theo code như bên dưới

@media print {
.print {
        display: block;
        /*break-before: always;*/
        page-break-before: always;
    }
}