Sử dụng DataList để hiển thị dữ liệu

Một phần của tài liệu Giáo trình xây dựng ứng dụng web(ngành hệ thống thông tin) (Trang 113)

Như điều khiển DataGrid, điều khiển DataList được sử dụng để hiển thị dữ liệụ Tuy nhiên, đối với DataList, chúng ta phải tự thiết kế hình thức hiển thị dữ liệu (giống như Template Column của DataGrid).

Một số thuộc tính cần chú ý của DataList:

 RepeatDirection: Qui định hướng hiển thị dữ liệu • Horizontal: Hiển thị dữ liệu theo chiều ngang lbmsg.Text = _matv; if (ẹCommandName == "New") { Grid.DataSourceID = ""; Grid.DataBind(); } }

KHOA CÔNG NGHỆ THÔNG TIN 111 • Vertical (mặc định): Hiển thị dữ liệu theo chiều đứng

 RepeatColumns: Qui định số cột hiển thị của DataList

Thiết kế hình thức hiển thị cho DataList cũng tương tự như thiết kế cho cột Template Column của DataGrid.

Chọn Edit Template | ItemTemplate từ thực đơn ngữ cảnh để thực hiện thiết kế hình thức hiển thị cho DataList.

Ví dụ: Hiển thị thông tin sách với DataList

Như cột Template Column của DataGrid, xử lý hiển thị dữ liệu cho DataList được viết trong sự kiện ItemDataBound. Xử lý nhấn của các Button đặt trong DataList được viết trong sự kiện ItemCommand.

KHOA CÔNG NGHỆ THÔNG TIN 112 <asp:DataList ID="Gridlist" runat="server" RepeatDirection="Horizontal"

RepeatColumns="4" CssClass="divpage"> <HeaderTemplate>

<div style="width: 100%; background-color: #d5ffff; height: 25px; pađing-top: 8px; font-weight: bold; color: Blue;">

>> DANH MỤC SẢN PHẨM </div> </HeaderTemplate>

<ItemTemplate>

<div class="divkhung">

<div class="divfont" style="color: Blue;"> Mã: <%#Eval("MASP")%></div>

<div class="divfont" style="font-weight: bold;"> <%#Eval("TENSP")%></div>

<div class="divfont" style="color: Blue;">

<a href='detail.aspx?masp=<%#Eval("MASP")%>'>

<asp:Image ID="image" runat="server" Width="150px" Height="200px" ImageUrl=<%#"~/images/"+Eval("HINH")%> />

</a> </div>

<div class="divfont" style="font-weight: bold;"> Đơn giá <%#Eval("GIA")%>

</div>

<div class="divfont" style="font-weight: bold;">

<asp:ImageButton ID="ImageButton1" ImageUrl="~/images/cart.gif" runat="server" />

</div> </div>

KHOA CÔNG NGHỆ THÔNG TIN 113 </ItemTemplate>

</asp:DataList> • Code C#

protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) LoadDL(); } void LoadDL() {

DataTable dt = new DataTable(); ClsData cls = new ClsDată);

dt = cls.getTable("select * from SANPHAM"); //dt = Loadproduct_en(changeid().Trim()); if (dt.Rows.Count > 0) Gridlist.Visible = true; else Gridlist.Visible = false; }

KHOA CÔNG NGHỆ THÔNG TIN 114

Hình 4-26 Hiển thị danh sách sản phẩm 4.8.2. Cập nhật dữ liệu với DataList

Ngoài việc hiển thị dữ liệu, DataList cũng hỗ trợ các thao tác cập nhật dữ liệụ Để thực hiện chức năng cập nhật dữ liệu với DataList, chúng ta cần phải thiết kế thêm vùng EditIemTemplate cho DataList. (xem hình)

Bước 1: Thiết kế

Code Html như sau:

<h3>Ví dụ Edit trên DataList</h3>

<asp:DataList ID="ItemsList" GridLines="Both" RepeatColumns="3" RepeatDirection="Horizontal" CellPađing="3" CellSpacing="0" runat="server">

KHOA CÔNG NGHỆ THÔNG TIN 115 <AlternatingItemStyle BackColor="Gainsboro"></AlternatingItemStyle> <EditItemStyle BackColor="yellow"></EditItemStyle> <HeaderTemplate> Danh sách demo </HeaderTemplate> <ItemTemplate> Mã: <%# DataBinder.Eval(Container.DataItem, "MASP") %><br /> Tên sp: <%# DataBinder.Eval(Container.DataItem, "TENSP") %> <br /> Giá: <%# DataBinder.Eval(Container.DataItem, "GIA", "{0:c}") %> <br />

<asp:LinkButton ID="EditButton" Text="Edit" CommandName="Edit" runat="server" />

</ItemTemplate> <EditItemTemplate> Mã:

<asp:Label ID="maLabel"

Text='<%# DataBinder.Eval(Container.DataItem, "MASP") %>' runat="server" />

<br /> Tên SP:

<asp:TextBox ID="tenTextBox"

Text='<%# DataBinder.Eval(Container.DataItem, "TENSP") %>' runat="server" />

KHOA CÔNG NGHỆ THÔNG TIN 116 <br />

Giá:

<asp:TextBox ID="giaTextBox"

Text='<%# DataBinder.Eval(Container.DataItem, "GIA", "{0:c}") %>' runat="server" />

<br />

<asp:LinkButton ID="UpdateButton" Text="Update" CommandName="Update" runat="server" />

<asp:LinkButton ID="DeleteButton" Text="Delete" runat="server" CommandName="Delete"/>

<asp:LinkButton ID="CancelButton" Text="Cancel" CommandName="Cancel" runat="server" />

</EditItemTemplate> </asp:DataList>

Bước 2: Xử lý lệnh để cập nhật dữ liệu

Xử lý các sự kiện EditCommand, CancelCommand, UpdateCommand để thực hiện/bỏ qua việc thay đổi dữ liệụ

DataTable Cart = new DataTable(); DataView CartView;

protected void Page_Load(object sender, EventArgs e) { GetSource(); if (!IsPostBack) { BindList(); }

KHOA CÔNG NGHỆ THÔNG TIN 117 ItemsList.EditCommand += new DataListCommandEventHandler(this.Edit_Command); ItemsList.UpdateCommand += new DataListCommandEventHandler(this.Update_Command); ItemsList.DeleteCommand += new DataListCommandEventHandler(this.Delete_Command); ItemsList.CancelCommand += new DataListCommandEventHandler(this.Cancel_Command); } void BindList() { ItemsList.DataSource = CartView; ItemsList.DataBind(); } void GetSource() {

// create it; otherwise, load the datạ if (Session["ShoppingCart"] == null) {

DataRow dr;

// Define the columns of the tablẹ

Cart.Columns.Ađ(new DataColumn("MASP", typeof(Int32))); Cart.Columns.Ađ(new DataColumn("TENSP", typeof(String))); Cart.Columns.Ađ(new DataColumn("GIA", typeof(Double))); Session["ShoppingCart"] = Cart;

KHOA CÔNG NGHỆ THÔNG TIN 118 { dr = Cart.NewRow(); if (i % 2 != 0) { dr[0] = 2; } else { dr[0] = 1; } dr[1] = "Item " + ịToString(); dr[2] = (1.23 * (i + 1)); Cart.Rows.Ađ(dr); } } else {

// Retrieve the sample data from session statẹ Cart = (DataTable)Session["ShoppingCart"]; }

// Create a DataView and specify the field to sort bỵ CartView = new DataView(Cart);

CartView.Sort = "TENSP"; return;

}

KHOA CÔNG NGHỆ THÔNG TIN 119 {

ItemsList.EditItemIndex = ẹItem.ItemIndex; BindList();

}

void Cancel_Command(Object sender, DataListCommandEventArgs e) {

ItemsList.EditItemIndex = -1; BindList();

}

void Delete_Command(Object sender, DataListCommandEventArgs e) {

// Retrieve the name of the item to removẹ

String item = ((Label)ẹItem.FindControl("ItemLabel")).Text; CartView.RowFilter = "Item='" + item + "'";

if (CartView.Count > 0) {

CartView.Delete(0); }

CartView.RowFilter = "";

// Set the EditItemIndex property to -1 to exit editing modẹ Be sure // to rebind the DataList to the data source to refresh the control. ItemsList.EditItemIndex = -1;

BindList(); }

void Update_Command(Object sender, DataListCommandEventArgs e) {

KHOA CÔNG NGHỆ THÔNG TIN 120 // Retrieve the updated values from the selected item.

String item = ((Label)ẹItem.FindControl("maLabel")).Text; String qty = ((TextBox)ẹItem.FindControl("tenTextBox")).Text; String price = ((TextBox)ẹItem.FindControl("giaTextBox")).Text; CartView.RowFilter = "Item='" + item + "'";

if (CartView.Count > 0) { CartView.Delete(0); } CartView.RowFilter = ""; DataRow dr = Cart.NewRow(); dr[0] = qty; dr[1] = item; if (price[0] == '$') { dr[2] = Convert.ToDouble(pricẹSubstring(1)); } else { dr[2] = Convert.ToDouble(price); } Cart.Rows.Ađ(dr); ItemsList.EditItemIndex = -1; BindList(); }

KHOA CÔNG NGHỆ THÔNG TIN 121

Hình 4-27 Giao diện thiết kế DataList 4.9. Điều khiển Repeater

Như 2 điều khiển DataList & DataGrid, điều khiển Repeater cũng được dùng để hiển thị dữ liệụ Tuy nhiên, để hiển thị dữ liệu, chúng ta phải tự thiết kế hình thức hiển thị thông qua các tag HTML.

Điều khiển Repeater có các tag sau:

 <HeaderTemplate></HeaderTemplate> (tùy chọn)

Qui định hình thức hiển thị cho tiêu đề. (Chỉ xuất hiện 1 lần, phía trên của điều khiển)  <ItemTemplate></ItemTemplate> (Bắt buộc phải có)

Qui định hình thức hiển thị cho các mục dữ liệu trong điều khiển.  <AlternatingItemTemplate></AlternatingItemTemplate> (tùy chọn)

Qui định hình thức hiển thị cho các mục dữ liệu trong điều khiển. Nội dung được qui định trong cặp tag này sẽ hiển thị xen kẽ với các nội dung trong cặp tag <ItemTemplate> </ItemTemplate>

 <SeparatorTemplate></SeparatorTemplate> (tùy chọn) Qui định hình thức hiển thị giữa các dòng dữ liệu

 <FooterTemplate></FooterTemplate> (tùy chọn)

Qui định hình thức hiển thị cho tiêu đề dướị (Chỉ xuất hiện 1 lần, phía dưới của điều khiển)

KHOA CÔNG NGHỆ THÔNG TIN 122 Bước 1. Tạo mới điều khiển Repeater: rptKhach_hang vào trang Web.

Bước 2. Chuyển qua xem trang Web dưới dạng HTML

Bước 3. Bổ sung các tag sau

<asp:Repeater id="rptKhach_hang" runat="server"> <HeaderTemplate>

<table border="1" bordercolor="SteelBlue"> <tr> <td width="130" align="center"> <strong>Họ khách hàng</strong> </td> <td width="100" align="center"> <strong>Tên khách hàng</strong> </td> <td width="120" align="center"> <strong>Địa chỉ</strong> </td> <td width="80" align="center"> <strong>Điện thoại</strong> </td>

<asp:Repeater id="rptKhach_hang" runat="server">

KHOA CÔNG NGHỆ THÔNG TIN 123 </tr> </HeaderTemplate> <ItemTemplate> <tr> <td> <%# Container.DataItem("Ho_khach_hang") %> </td> <td> <%# Container.DataItem("Ten_khach_hang") %> </td> <td> <%# Container.DataItem("Dia_chi")%> </td> <td> <%# Container.DataItem("Dien_thoai") %> </td> </tr> </ItemTemplate> <AlternatingItemTemplate> <tr bgcolor="GhostWhite"> <td> <%# Container.DataItem("Ho_khach_hang") %> </td> <td> <%# Container.DataItem("Ten_khach_hang") %> </td>

KHOA CÔNG NGHỆ THÔNG TIN 124 <td> <%# Container.DataItem("Dia_chi")%> </td> <td> <%# Container.DataItem("Dien_thoai") %> </td> </tr> </AlternatingItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:Repeater>

Bước 4. Xem lại màn hình thiết kế

Bước 5. Tạo nguồn dữ liệu cho điều khiển

protected void Page_Load(object sender, EventArgs e) {

if (!IsPostBack) LoadKH(); }

KHOA CÔNG NGHỆ THÔNG TIN 125 void LoadKH()

{

DataTable dt = new DataTable();

string str = "SELECT * FROM KHACHHANG"; dt = cls.getTable(str); if (dt.Rows.Count > 0) { rptnv.DataSource = dt; rptnv.DataBind(); } } Bước 6. Chạy ứng dụng 4.10. Bài tập áp dụng

1. Viết chương trình hiển thị danh sách sinh viên từ cơ sở dữ liệủ Khi người dùng chọn vào một 1 sinh viên thì thông tin sinh viên đó hiển thị ở trang chi tiết thông tin sinh viên? 2. Viết chương trình hiển thị danh sách sản phẩm trên DataList và cho phép phân trang? Khi người dùng muốn xem chi tiết sản phẩm thì click vào tên sản phẩm đó, chuyển trang sang chi tiết sản phẩm?

KHOA CÔNG NGHỆ THÔNG TIN 126

CHƯƠNG 5: XÂY DỰNG VÀ QUẢN LÝ ỨNG DỤNG

Giới thiệu: Giới thiệu về các đối tượng như Request, Response, Application và cấu hình website web.config

Mục tiêu:

- Trình bày được các kiến thức về trạng thái của ứng dụng Web - Trình bày được các chức năng của các control quản lý trạng thái - Xây dựng được ứng dụng có chức năng quản lý trạng thái

Nội dung chính:

5.1. Đối tượng Request

Đối tượng Request được dùng để nhận thông tin từ trình duyệt của người dùng gởi về cho Web Server. Thuộc tính QueryString

Như chúng tôi đã trình bày ở phần đầu của cuốn sách này, HTTP được xác định qua URLs (Uniform Resource Locators), với cấu trúc chuỗi có định dạng như sau:

http: // <host> [: <port>] [ <path> [? <QueryString>]]

Phần cuối của chuỗi URL là QueryString - còn được gọi là chuỗi tham số, có cấu trúc như sau:

[?Tham_so_1=gia_tri_1[&Tham_so_2=gia_tri_2[&……]]]

Trong trường hợp có nhiều tham số, các cặp [<Tham_so> = <Gia_tri>] phân cách nhau bằng dấu &

Ví dụ 1:

http://www.ktkthcm.edụvn/Index.aspx?PID=16

http://www. ktkthcm.edụvn/Index.aspx?ArticleID=89211&PID=16

Thuộc tính QueryString của đối tượng Request cho phép chúng ta nhận các giá trị truyền qua chuỗi tham số nàỵ

Request.QueryString("Tên_tham_số")

KHOA CÔNG NGHỆ THÔNG TIN 127 "Request.aspx?Chuc_nang=Hieu_chinh&ID=123". Để lấy giá trị 2 tham số trong chuỗi QueryString, chúng ta thực hiện như sau:

string sChuc_nang; sChuc_nang = Request.QueryString("Chuc_nang"); lblChuc_nang.Text = sChuc_nang; int Id; Id = Request.QueryString("ID"); lblId.Text = Id;

Trong trường hợp tên tham số không tồn tại trong chuỗi QueryString, thuộc tính Request.QueryString() sẽ trả về giá trị nothing.

5.2. Đối tượng Response 5.2.1. Đối tượng Response 5.2.1. Đối tượng Response

Đối tượng Response được sử dụng để giao tiếp với Client, nó quản lý và điều phối thông tin từ Web Server đến các trình duyệt của người dùng.

Phương thc Write

Phương thức Write của đối tượng Response được dùng để in ra một chuỗi trên trang Web. Phương thức này là một trong những phương thức chủ lực trong các ứng dụng web sử dụng ASP 3.0 khi cần gởi kết quả từ Server về cho Client.

ResponsẹWrite("Chào bạn. Bạn đang tìm hiểu về đối tượng Responsẹ")

KHOA CÔNG NGHỆ THÔNG TIN 128 lblChaọText = "Chào bạn. Bạn đang tìm hiểu về đối tượng Responsẹ" ;

Qua ví dụ trên, chắc có lẽ bạn cũng nhận ra rằng, khi sử dụng phương thức ResponsẹWrite, chúng ta không thể qui định vị trí hiển thị của chuỗi trên trong trang Web. Thay vào đó, với ASP.Net, thông qua các Server control, chúng ta có thể thực hiện chức năng tương tự nhưng linh hoạt hơn bằng cách đặt điều khiển tại vị trí cần hiển thị.

Phương thc Redirect

Phương thức Redirect gởi thông điệp yêu cầu Web Browser truy cập đến một địa chỉ khác.

Ví dụ 1:

'Nếu đăng nhập thành công

if <Kiểm tra đăng nhập>

ResponsẹRedirect("Chaọaspx") ; else

ResponsẹRedirect("Dang_nhap.aspx") ;

5.2.2. Ví dụ xử lý cho phép người dùng download file

Ví dụ 2: Xử dụng đối tượng Response để thực hiện việc download tập tin.

Viết lệnh xử lý:

private void lnkDownload_Click(object sender, object e) {

KHOA CÔNG NGHỆ THÔNG TIN 129 string sDuong_dan;

sDuong_dan = Server.MapPath("../Download/") + sTap_tin;

ResponsẹAđHeader("Content-Disposition", "attachment; filename=" + sTap_tin); ResponsẹWriteFile(sDuong_dan); ResponsẹEnd(); } Kết quả thực hiện 5.3. Session

Application và Session là 2 đối tượng khá quan trọng trong ứng dụng web, giúp các trang aspx có thể liên kết và trao đổi dữ liệu cho nhaụ Trong phần này, chúng ta sẽ tìm hiểu và sử dụng 2 đối tượng này trong ứng dụng.

KHOA CÔNG NGHỆ THÔNG TIN 130

Hình 5-1 Mối quan hệ giữa Session và Application

Đối tượng Session được dùng để lưu trữ thông tin của người dùng trong ứng dụng. Thông tin được lưu trữ trong Session là của một người dùng trong một phiên làm việc cụ thể. Web Server sẽ tự động tạo một đối tượng Session cho mỗi người dùng mới kết nối vào ứng dụng và tự động hủy chúng nếu người dùng còn không làm việc với ứng dụng nữạ

Tuy nhiên, không giống như đối tượng Application, đối tượng Session không thể chia sẻ thông tin giữa những lần làm việc của người dùng, nó chỉ có thể cung cấp, trao đổi thông tin cho các trang trong lần làm việc tương ứng.

Trong ứng dụng web, đối tượng Session giữ vai trò khá quan trọng. Do sử dụng giao thức HTTP, một giao thức phi trạng thái, Web Server hoàn toàn không ghi nhớ những gì giữa những lần yêu cầu của Client. Đối tượng Session tỏ ra khá hữu hiệu trong việc thực hiện "lưu vết và quản lý thông tin của người dùng".

5.3.1. Thuộc tính & Phương thức Thuộc tính Timeout Thuộc tính Timeout

Qui định khoảng thời gian (tính bằng phút) mà Web Server duy trì đối tượng Session nếu người dùng không gởi yêu cầu nào về lại Server. Giá trị mặc định của thuộc tính này là 20.

KHOA CÔNG NGHỆ THÔNG TIN 131 Nếu không có yêu cầu nào kể từ lần yêu cầu sau cùng một khoảng thời gian là <Timeout> phút, đối tượng Session mà Web server cấp cho lần làm việc đó sẽ tự động được giải phóng. Những yêu cầu sau đó được Web server coi như là một người dùng mới, và đương nhiên sẽ được cấp một đối tượng Session mớị

Phương thức Abandon

Như các bạn đã biết, trong khoảng thời gian <Timeout> phút kể từ lần yêu cầu sau cùng của Client, đối tượng Session vẫn được duy trì dù cho không có sự tương tác nào của Client. Điều này đồng nghĩa với việc Web server phải sử dụng một vùng nhớ để duy trì đối tượng Session trong một khoảng thời gian tương ứng.

Phương thức Abandon của đối tượng Session sẽ giải phóng vùng nhớ được dùng để duy trì đối tượng Session trên Web Server ngay khi được gọi thực hiện. Những yêu cầu sau đó được Web server coi như là một người dùng mớị

5.3.2. Sử dụng biến toàn cục với Session

Tạo biến Session

Session("Tên biến") = <giá trị> Lấy giá trị từ biến Session

<biến> = Session("Tên biến")

Lưu trữ thông tin khi người dùng chưa đăng nhập hệ thống: Session("Mkh") = 0

Session("Ten_dang_nhap") = ""

Khi người dùng đăng nhập hệ thống thành công, cập nhật lại thông tin đăng nhập của người dùng được lưu trên Session.

Session("Mkh") = 1

Session("Ten_dang_nhap") = "qdang2007" Duyệt qua tập hợp biến chứa trong Session

for (int i = 0; i <= Session.Count() - 1; i++) {

ResponsẹWrite(Session.Keys(i) + " : "); ResponsẹWrite(Session(i) + "<br/>"); }

KHOA CÔNG NGHỆ THÔNG TIN 132

5.4. Application

Đối tượng Application được sử dụng để quản lý tất cả các thông tin của một ứng dụng web. Thông tin được lưu trữ trong đối tượng Application có thể được xử lý trong bất kỳ trang aspx nào trong suốt chu kỳ sống của ứng dụng.

5.4.1. Sử dụng biến Application

Tạo biến Application

Application("Tên biến") = <giá trị> Lấy giá trị từ biến Application

<biến> = Application("Tên biến") Ví dụ:

Application.Lock()

Application("So_lan_truy_cap") = 0 Application("So_nguoi_online") = 0 Application.UnLock()

Chú ý: Do tại một thời điểm có thể có nhiều người cùng lúc truy cập và thay đổi giá trị của các thông tin được lưu trong đối tượng Application, chúng ta nên sử dụng bộ lệnh Lock và UnLock ngay trước và sau khi cập nhật giá trị của biến Application.

Biến Application có thể được sử dụng ở bất kỳ trang nào và được duy trì trong suốt chu kỳ sống của ứng dụng.

5.4.2. Duyệt qua tập hợp biến chứa trong Application

int i;

ResponsẹWrite(@"<b><u>Danh sách các biến trong đối tượng Application</u></b><br>");

for (i = 0; i <= Application.Count() - 1; i++) { ResponsẹWrite(Application.Keys(i) + " : "); ResponsẹWrite(Application(i) + "<br />"); } 5.5. Cookies 5.5.1. Giới thiệu

Có lẽ bạn cũng đã từng đăng ký là một thành viên của một trang web hay một forum nào đó, và chắc cũng không ít lần ngạc nhiên khi bạn vừa yêu cầu đến một trang

KHOA CÔNG NGHỆ THÔNG TIN 133 web hay forum mà bạn đã đăng ký trước đó, trang web nhận ngay ra, bạn chính là thành viên của họ và gởi ngay lời chào đến bạn, chẳng hạn: Chào Nguyễn Đăng.

Làm sao mà Web Server nhận ra được mình nhỉ? Mình đã đăng ký từ ngày hôm qua kia mà? Không đâu xa cả, những thông tin đó được lưu ngay chính tại máy của bạn. Những thông tin được Web Server lưu tại máy Client được gọi là Cookies.

Không giống như đối tượng Session, đối tượng Cookies cũng được dùng để lưu trữ thông tin của người dùng, tuy nhiên, thông tin này được lưu ngay tại máy gởi yêu cầu đến Web Server.

Có thể xem một Cookie như một tập tin (với kích thước khá nhỏ) được Web Server lưu tại máy của người dùng. Mỗi lần có yêu cầu đến Web Server, những thông tin của Cookies cũng sẽ được gởi theo về Server.

Hình 5-2 Mô hình làm việc của Cookies 5.5.2. Làm việc với Cookies

Thêm Cookies

ResponsẹCookies.Ađ(<HttpCookie>) Ví dụ:

HttpCookie cookTen_dn = new HttpCookie("Ten_dang_nhap"); cookTen_dn.Value = txtTen_dang_nhap.Text;

cookTen_dn.Expires = DateTimẹTodaỵAđDays(1); ResponsẹCookies.Ađ(cookTen_dn);

Trong ví dụ trên, chúng ta đã tạo ra Cookies có tên là Ten_dang_nhap lưu trữ tên đăng nhập của người dùng. Thông tin này sẽ được lưu trữ trên Cookies 1 ngày kể từ

Một phần của tài liệu Giáo trình xây dựng ứng dụng web(ngành hệ thống thông tin) (Trang 113)

Tải bản đầy đủ (PDF)

(178 trang)