Trong phần này, chúng ta sẽ kiểm tra các phương thức và view đã được tạo cho SanPham controller. Sau đó chúng ta sẽ thêm mới trang search.
Chạy ứng dụng và browse đến controller SanPham bằng cách thêm /SanPham vào URL. Click vào liên kết Edit để thấy URL được liên kết tới.
Liên kết Edit đã được tao ra bởi phương thức Html.ActionLink trong view Views\SanPham \Index.cshtml:
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
Đối tượng Html là một hepler, các thuộc tính của đối tượng này thuộc class WebViewPage. phương thức ActionLink giúp chúng ta dễ dàng tạo ra các siêu liên kết HTML động liên kết đến các phương thức trên controller. Argument đầu tiên của phương thức này là link text (ví dụ, Edit). Argument thứ hai là tên của phương thức gọi ra. cuối cùng là một đối tượng anonymous để tạo ra đường đi (trong trường hợp này là giá trị của ID là 2).
Liên kết được tạo ra trong ảnh trước đó là http://localhost:xxxxx/SanPham/Edit/2. URL mặc định chúng ta nhận được có dạng {controller}/{action}/{id}.
Vì thế, ASP.NET phiên dịch http://localhost:xxxxx/SanPham/Edit/2 thành một yêu cầu đến phương thức Edit của SanPham controller với tham số ID là 2.
Ngoài ra chúng ta có thể truyền tham số vào cho phương thức bằng cách sử dụng chuỗi truy vấn.
Ví dụ, một URL http://localhost:xxxxx/SanPham/Edit?ID=2 để truyền tham số ID là 2 cho phương thức edit của SanPham controller.
Mở controller SanPham và xem 2 phương thức sau:
// GET: /SanPham/Edit/5
public ActionResult Edit(int id)
{
SanPham sanpham = db.SanPhams.Find(id);
return View(sanpham);
}
//// POST: /SanPham/Edit/5
[HttpPost]
public ActionResult Edit(SanPham sanpham)
{
if (ModelState.IsValid) {
db.Entry(sanpham).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(sanpham);
}
Lưu ý là phương thức Edit được xử lí bởi thuộc tính HttpPost. Thuộc tính này chỉ định rằng sự nạp chồng phương thức Edit có thể được gọi ra cho POST request. Chúng ta có thể áp dụng thuộc tính HttpGet cho phương thức edit đầu tiên, nhưng không cần thiết bởi vì nó đã mặc định như thế.
Phương thức HttpGet Edit nhận vào tham số là ID của SanPham, sau đó sẽ tìm SanPham bằng cách sử dụng phương thức EF Find, và trả về SanPham được chọn để Edit view. Khi hệ thống scaffold tạo Edit view, nó sẽ kiểm tra class SanPham và tao code để render ra thành phần <label> và <input> cho mỗi thuộc tính của class. Ví dụ sau cho thấy Edit view đã được tạo:
@model NguyenIchHoan.Models.SanPham
@{ ViewBag.Title = "Edit";
}
<h2>Edit</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"
type="text/javascript"></script>
<script
src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"
type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>SanPham</legend>
<div class="editor-label">
@Html.LabelFor(model => model.masp)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.masp)
@Html.ValidationMessageFor(model => model.masp)
</div>
@Html.HiddenFor(model => model.ID)
<div class="editor-label">
@Html.LabelFor(model => model.tensp)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.tensp)
@Html.ValidationMessageFor(model => model.tensp)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.mancc)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.mancc)
@Html.ValidationMessageFor(model => model.mancc)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.madongsp)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.madongsp)
@Html.ValidationMessageFor(model => model.madongsp)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.mota)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.mota)
@Html.ValidationMessageFor(model => model.mota)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.anh)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.anh)
@Html.ValidationMessageFor(model => model.anh)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.thongtinthem)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.thongtinthem)
@Html.ValidationMessageFor(model => model.thongtinthem)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ngaynhaphang)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ngaynhaphang)
@Html.ValidationMessageFor(model => model.ngaynhaphang)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.dongia)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.dongia)
@Html.ValidationMessageFor(model => model.dongia)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
Scaffold code sử dụng một vài phương thức helper để tổ chức luồng HTML markup. Html.LabelFor dùng để hiển thị tên trường (ví dụ như mã sản phẩm, tên sản phẩm, đơn giá, mã nhà cung cấp,....). Html.EditorFor hiển thị một thẻ <input>. Html.ValidationMessageFor hiển thị bấy kì tin nhắn kiểm tra dữ liệu liên kết với thuộc tính đó.
(Scaffold là có nghĩa là giàn giáo. Ở nước ngoài, giàn giáo xếp lại được, khi cần dựng lên, ghép cao hơn để xây dựng. Thuật ngữ Scaffold xuất hiện phổ biến trong Ruby On Rails để mô tả về khung mã nguồn tự động sinh ra cho các hàm Create, Read, Update, Delete (CRUD). Như vậy lập trình không phải viết nhiều đoạn code lặp đi lặp lại nữa)
Chạy ứng dụng và điều hướng đến /SanPham URL. Click liên kết Edit.
Trong trình duyệt, xem source của trang chúng ta sẽ thấy như trong ví dụ sau:
Thành phần <input> là một thành phần của HTML Form mà thuộc tính action được set post đến URL /SanPham/Edit. Dữ liệu form sẽ được post đến server khi button Edit được click.
Xử lí POST request
Đoạn code sau đây trình bày phiên bản HttpPost của phương thức Edit:
[HttpPost]
public ActionResult Edit(SanPham sanpham)
{
if (ModelState.IsValid) {
db.Entry(sanpham).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(sanpham);
}
ASP.NET framework model gắn kết các giá trị của form được post và tạo một đối tượng SanPham được truyên đi như một tham số.
Model.IsValid kiểm tra dữ submit trong form có thể dùng để điều chỉnh đối tượng SanPham. Nếu dữ liệu là hợp lệ, code xử lí sẽ lưu dữ liệu SanPham đến đối tượng SanPham collection của SanPhamDBContext.
Sau đó sẽ lưu dữ liệu SanPham mới này nào database bằng cách gọi phương thức SaveChanges của SanPhamDBContext để lưu thay đổi vào database. Sau khi lưu dữ liệu, code sẽ redirect người dùng đến phương thức Index của class SanPham Controller, và hiển thị danh sách các sản phẩm vừa được cập nhật.
Làm cho phương thức Edit trở nên mạnh mẽ hơn
Phương thức HttpGet Editđược sinh ra bởi hệ thống scafffolding không có kiểm tra dữ liệu được truyền vào (trong trường hợp này là ID). Nếu người dùng bỏ đi phần ID của URL (http://localhost:xxxxx/SanPham/Edit) sẽ xuất hiện lỗi như sau:
Ngoài ra người dùng có thể truyền vào ID không tồn tại trong cơ sở dữ liệu, ví dụhttp://localhost:xxxxx/SanPham/Edit/1234. Chúng ta có thể tránh xảy ra lỗi này bằng cách điều chỉnh phương thức Http Edit. Trước hết, thay đổi tham số ID về giá trị mặc định là 0 khi ID được truyền vào không rõ ràng. Ngoài ra chúng ta có thể kiểm tra bằng phương thức Find để tìm một sản phẩm tồn tại thực sự trước khi return đối tượng SanPham về cho view template. Phương thức Edit được cập nhật như sau:
public ActionResult Edit(int id)
{
SanPham sanpham = db.SanPhams.Find(id);
if (sanpham == null)
{
return HttpNotFound();
}
return View(sanpham);
}
Nếu như không tìm thấy phim, phương thức HttpNotFound sẽ được gọi và hiển thị ra một trang trắng để không gây lỗi khi sử dụng trang web:
Tất cả các phương thức HttpGet sau đây điều có cùng mẫu (pattern) tương tự nhau. Chúng lấy một đối tượng (hoặc danh sách các đối tượng, trong trường hợp này là phương thức Index), và truyền model đến view. Phương thức create truyền một đối tượng SanPham rỗng đến Create view. Tất cả các phương thức create, edit, delete, hoặc các phương thức điều chỉnh dữ liệu khác cũng thực hiện tương tự trong nạp chồng phương thức HttpPost.
Thêm phương thức Search và Search View
Trong phần này chúng ta sẽ thêm một phương thức SearchIndex cho phép chúng ta tìm kiếm các sản phẩm theo tên hoặc mã dòng sản phẩm. URL sử dụng cho phương thức này là /SanPham /SearchIndex. Yêu cầu hiển thị dưới dạng HTML form chứa input cho phép người dùng điền thông tin tìm kiếm. Khi người dùng submit form, phương thức sẽ lấy giá trị tìm kiếm được nhập vào bởi người dùng và sử dụng giá trị đó để tìm kiếm trong database.
Hiển thị form SearchIndex
Bắt đầu bằng cách thêm một phương thức SearchIndex vào class SanPhamController. Phương thức này sẽ trả về một view chứa đựng HTML form.
Đây là code:
public ActionResult SearchIndex(string searchString)
{
var sanpham = from m in db.SanPhams
select m;
if (!String.IsNullOrEmpty(searchString)) {
sanpham = sanpham.Where(s =>
s.tensp.Contains(searchString));
}
return View(sanpham);
Dòng đầu tiên của phương thức là tạo một truy vấn LINQ để chọn ra các sản phẩm thỏa điều kiện tìm kiếm:
var sanpham = from m in db.SanPhams
select m;
Nếu tham số searchString chứa chuỗi, câu truy vấn sẽ được điều chỉnh để lọc kết quả dựa trên chuỗi giá trị tìm kiếm, sử dụng code sau đây:
if (!String.IsNullOrEmpty(searchString)) {
sanpham = sanpham.Where(s =>
s.tensp.Contains(searchString));
}
Truy vấn LINQ không thực thi ngay khi được định nghĩa hoặc khi chúng được điều chỉnh bằng cách gọi một phương thức như Where hoặc OrderBy. Thay vào đó, việc thực thi truy vấn sẽ được hoãn lại. Trong ví dụ SearchIndex, truy vấn được thực thi trong SearchIndex view. Để biết thêm thông tin về hoãn thực thi truy vấn, chúng ta có thể xemQuery Execution
Bây giờ chúng ta đã có thể triển khai SearchIndex view, view này sẽ hiển thị form cho người dùng. Click phải vào phương thức SearchIndex và sau đó click Add View. Trong họp thoại Add View, chỉ định như trong hình để truyền một đối tượng SanPham đến view template. Trong danh sách scaffold template, chọn List, sau đó click Add.
b
Khi chúng ta click Add, view template Views\SanPham
\SearchIndex.cshtml sẽ được tạo. Bởi vì chúng ta đã chọn trong danh sách scaffold template, Visual web developer tự động sinh ra nội dung (code) mặc định
trong view. Scaffolf đã tạo một HTML form. Nó kiểm tra class SanPham và đã tạo ra code để render ra thành phần <label> cho mỗi thuộc tính của class. Sau đây là code sinh ra khi tạo view:
@model IEnumerable<NguyenIchHoan.Models.SanPham>
@{ ViewBag.Title = "SearchIndex";
}
<h2>SearchIndex</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
masp
</th>
<th>
tensp
</th>
<th>
mancc
</th>
<th>
madongsp
</th>
<th>
mota
</th>
<th>
anh
</th>
<th>
thongtinthem
</th>
<th>
ngaynhaphang
</th>
<th>
dongia
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.masp)
</td>
<td>
@Html.DisplayFor(modelItem => item.tensp)
</td>
<td>
@Html.DisplayFor(modelItem => item.mancc)
</td>
<td>
@Html.DisplayFor(modelItem => item.madongsp)
</td>
<td>
@Html.DisplayFor(modelItem => item.mota)
</td>
<td>
@Html.DisplayFor(modelItem => item.anh)
</td>
<td>
@Html.DisplayFor(modelItem => item.thongtinthem)
</td>
<td>
@Html.DisplayFor(modelItem => item.ngaynhaphang)
</td>
<td>
@Html.DisplayFor(modelItem => item.dongia)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
@Html.ActionLink("Details", "Details", new { id=item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
Đầu tiên trong bảng của chúng ta gồm có tất cả các bản ghi là:
Chạy ứng dụng và điều hướng đến /SanPham/SearchIndex. Thêm vào url chuỗi truy vấn ?searchString=điện thoại. Các bộ sản phẩm đã lọc ra với tên sản phẩm= điện thoại được hiển thị.
Ta thử với chuỗi tìm kiếm khác là “máy tính” thì kết quả
Hoặc để trống chuỗi tìm kiếm:
Nếu chúng ta điều chỉnh phương thức SearchIndex để có một tham số với tên là id, tham số id này sẽ được ghép với vị trí {id} cho đường dẫn mặc định được gán trong tập tin Global.asax.
{controller}/{action}/{id}
Phương thức SearchIndex được điều chỉnh như sau:
public ActionResult SearchIndex(string id)
{
string searchString = id;
var sanpham = from m in db.SanPhams
select m;
if (!String.IsNullOrEmpty(searchString)) {
sanpham = sanpham.Where(s =>
s.tensp.Contains(searchString));
}
return View(sanpham);
}
Bây giờ chúng ta có thể truyền giá trị tìm kiếm như một đường dẫn dữ liệu (một phần của URL) thay vì phải truyền một chuỗi truy vấn giá trị.
Tuy nhiên, chúng ta không thể mong đợi người dùng điều chỉnh URL cho mỗi lần tìm kiếm. vì vậy, bây giờ chúng ta sẽ tạo thêm một User Interface để giúp họ lọc ra các sản phẩm, thay đổi phương thức SearchIndex để nhận vào chuỗi tham số có tên searchString:
Mở tập tin Views\SanPham\SearchIndex.cshtml, thêm đoạn mã sau vào sau @Html.ActionLink(“Create New”, “Create”)
@using (Html.BeginForm()) {
<p>Nhập nội dung tìm kiếm là tên sản phẩm :
@Html.TextBox("SearchString")
<input type="submit" value="Tìm Kiếm sản phẩm" /></p>
}
Html.BeginForm tạo ra một form dạng post back khi người dùng submit form bằng cách click vào nút “Tìm Kiếm Sản Phẩm”.
Hãy chạy ứng dụng lên:
Và thử tìm kiếm một sản phẩm theo tên là “điện thoại”.
Hoặc tên sản phẩm là “máy tính”:
Sẽ không có nạp chồng phương thức HtpPost SearchIndex. Chúng ta không cần nó, bởi vì phương thức này không làm thay đổi trạng thái của ứng dụng mà nó chỉ lọc dữ liệu.
Chúng ta có thể thêm phương thức HttpPost SearchIndex. trong trường hợp này, hành động gọi ra sẽ được ghép với phương thức HttpPost SearchIndex, và phương thức này sẽ chạy như hình hiển thị bên dưới.
Để giải quyết vấn đề trên là sử dụng nạp chồng phương thức của BeginForm chỉ định rõ POST request nên thêm vào thông tin tìm kiếm vào URL và thông tin này sẽ được gửi đến HttpGet của phương thức SearchIndex. Đặt các tham số sau vào phương thức BeginForm như sau:
@using (Html.BeginForm("SearchIndex","SanPham",FormMethod .Post))
Ở trong cửa sổ Code sẽ hiện lên chú thích cho phương thứ BeginForm
Bầy giờ chúng ta submit một tìm kiếm, URL chứa một chuỗi truy vấn. Tìm kiếm sẽ đi đến phương thức HttpGet SearchIndex, thậm chí chúng ta có phương thức HtpPost SearchIndex.
Truyền bằng phương thức GET khi truyền qua URL
Truyền bằng phương thức POST khi bấm nút tìm kiếm sản phẩm:
Thêm tìm kiếm theo dòng sản phẩm
Nếu chúng ta đã thêm một phiên bản HttpPost của phương thức SearchIndex thì hãy xóa nó đi.
Tiếp theo, chúng ta sẽ thêm một tính năng mới cho phép người dùng tìm kiếm các sản phẩm theo dòng sản phẩm. Sửa lại đoạn mã sau trong phương thức SearchIndex:
public ActionResult SearchIndex(string madongSP, string
searchString) {
var ListDongSP= new List<string>();
var QueryDongSp = from d in db.SanPhams
orderby d.madongsp select d.madongsp;
ListDongSP.AddRange(QueryDongSp.Distinct());
ViewBag.madongSp = new SelectList(ListDongSP);
var sanpham = from m in db.SanPhams
select m;
if (!String.IsNullOrEmpty(searchString)) {
sanpham = sanpham.Where(s => s.tensp.Contains(searchString));
}
if (string.IsNullOrEmpty(madongSP)) return View(sanpham);
else {
return View(sanpham.Where(x => x.madongsp ==
madongSP));
} }
Phương thức phương thức SearchIndex nhận vào một tham số là tên thể loại. Dòng đầu tiên của đoạn mã trên là tạo một danh sách đối tượng để lưu trữ các thể loại phim từ cơ sở dữ liệu.
Đoạn mã sau đây là một truy vấn LINQ để lấy tất cả các thể loại trong cơ sở dữ liệu.
var QueryDongSp = from d in db.SanPhams
orderby d.madongsp select d.madongsp;
Đoạn mã sử dụng phương thức AddRange của generic List collection để thêm tất cả các thể loại(Không trùng nhau) vào trong list.
ListDongSP.AddRange(QueryDongSp.Distinct());
Dòng tiếp theo sau dùng để lưu danh sách các thể loại vào trong đối tượng ViewBag.
ViewBag.madongSp = new SelectList(ListDongSP);
Đoạn mã sau dùng để kiểm tra tham số madongSp truyền vào. Nếu tham số truyền vào khác rỗng, kết quả trả về là danh sách cácsản phẩmđược chọn thỏa điều điều kiện là tên thể loại có chứa giá trị của tham số truyền vào.
if (string.IsNullOrEmpty(madongSP)) return View(sanpham);
{else
return View(sanpham.Where(x => x.madongsp == madongSP));
}
Ta sẽ test thử với chuỗi URL: http://localhost:xxxx /SanPham/SearchIndex?madongSP=DTDD