I have an existing web application built using ASP.NET WebForms and I am converting it to MVC 4.0. I have an administrative page that allows user to do CRUD operations on same page for employee such as edit address or add multiple addresses at same time by dynamically adding usercontrols. I have implemented ListView for displaying, editing and saving on same page. Now if I want to achieve same thing i.e. display/Edit/Save on the same view in MVC could someone suggest good practices for such scenario. (p.s. I have partial views ready for such CRUD operations)
Any help will be greatly appreciated.
Yes there are many way you can achieve this in MVC. Just like ListView,there are many third party controls which acts as ListView in MVC. But if you don not want to use those third party controls,then you can go with Table,Tr and Td. For that purpose, lets take an example. Your model is returning the list of data so that you need to display that list on the View. So get that list and use foreach loop and just use Table,TH,TR and TD. You can use #Html.ActionLink for Edit,Delete,etc. Hope this will help you.
I have implemented the similar thing in the MVC:
View:
// Creating html Table from data present in model
<table class="content-wrapper">
<tr>
<th>
#Html.DisplayName("Name")
</th>
<th>
#Html.DisplayName("ID")
</th>
<th>
#Html.DisplayName("Designation")
</th>
<th>
</th>
</tr>
#foreach (var item in Model.lstEmployees)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
<td>
#Html.DisplayFor(modelItem => item.id)
</td>
<td>
#Html.DisplayFor(modelItem => item.designation)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.id })
#Html.ActionLink("Delete", "Delete", new { id = item.id })
</td>
</tr>
}
Controller:
public ActionResult Delete(Data model)
{
//Code for delete
return View("Index", data);
}
[HttpGet]
public ActionResult Edit(Int32 Id)
{
//code for binding the existing records
return View(_data);
}
[HttpPost]
public ActionResult Edit(string sampleDropdown, Data model)
{
//code for saving the updated data
return RedirectToAction("Index", "Home");
}
As I wanted to use the same view to show/edit/save, I found a solution to implement AJAX and render partial views for CRUD operations. This can be achieved in many ways but I selected two options:
Using #Ajax.BeginForm and jquery.unobtrusive-ajax.min and just fetching partialview.
Using jQuery AJAX to acheive this.
Here is a link I found in Stackoverflow very helpful:
Using Ajax.BeginForm with ASP.NET MVC 3 Razor
(Thanks all for your effort)
Related
How do I make the HTML table display 10 records only and whenever it goes beyond 10 it will display a link for pages below? e.g. "1, 2, 3.." And limits up to 7 links like how YouTube displays it (See image below)? I'm using ASP.Net MVC with Bootstrap by the way.
<table id="userTbl" onclick="getTblRec('userTbl,'userBody','0')" class="table-scroll table-striped bootgrid-table">
<thead>
<tr>
<th class="hidden">
#Html.DisplayNameFor(model => model.USR_ID)
</th>
<th class="hidden">
#Html.DisplayNameFor(model => model.USR_FNAME)
</th>
</tr>
</thead>
<tbody id="userBody">
#foreach (var item in Model)
{
<tr>
<td id="userId" class="hidden">
#Html.DisplayFor(modelItem => item.USR_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.USR_FNAME)
</td>
<td>
</tr>
}
</tbody>
</table>
YouTube sample pic:
There are two ways of implementing pagination, Server and Client side. Firstly server implementation, Load only the set of items that are to be shown for the page from the server along with the page options. Pagination at the client side, load the entire set of items and provide pagination with the support of table and/or other controls. Both the options have pros and cons. These links should get you started on the topic,link1 , link2.
Since you are using ASP.NET MVC, there is an build in helper named WebGrid for scenarios like paging. This is super easy to use and provides almost all the functionality that you may need.
You can also take a look at this beginner level walk through.
WebGrid in asp.net mvc (By Sheo Narayan).
Make a partial view for paging and call that partial view if records you have more than 10. i.e. in this link Paging
Or you can install this nuget also, and your wish style would be able to design this is link for nuget Nuget Packege
The model that is being displayed in my view has been filtered by user action so some of the original data is no longer there. Paying attention to the ActionLink for EditRow, this is how my view displays the model:
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.User.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.User.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.User.Email)
</td>
<td>
#item.Weekly.WeekBeginning.ToShortDateString() - #item.Weekly.WeekEnding.ToShortDateString()
</td>
<td>
#(item.WeeklyTargetId != ViewBag.Edited ? Html.DisplayFor(modelItem => item.Hours) : Html.EditorFor(modelItem => item.Hours))
</td>
<td>
//here is the line I am trying to pass the model through:
#Html.ActionLink("Edit", "EditRow", new {id = item.WeeklyTargetId, currentSelection = Model}) |
#Html.ActionLink("Details", "Details", new {id = item.WeeklyTargetId}) |
#Html.ActionLink("Delete", "Delete", new {id = item.WeeklyTargetId})
</td>
</tr>
}
In the ActionLinkfor EditRow I was able to easily pass the id of each item through, but when I added currentSelection = Model or even = Model.ToList(), the controller method receives a count of 0.
Here is the Action signature I am using:
//I've tried IQueryable<WeeklyTarget> as well
public ActionResult EditRow(int? id, List<WeeklyTarget> selection )
My question is how can I pass the current(filterd) model being displayed in the view to the controller action? Should I be going about this a different way?
This is not the correct way to implement this, but if you MUST do it this way you would be better off passing the Ids from each item in Model rather than the Model objects themselves. Then in the Edit (GET) method, you can get those full objects from the DB using those IDs.
The intention of this code is not clear to me though. If every row has an "Edit" link, then I would assume that clicking that would only care about that specific row and not the entire list. More detail would be helpful to better answer the question.
UPDATE:
As discussed below, the best way to go about this would be with AJAX(recommend using jQuery). Upon click on a edit link, you should initiate a click handler in JS:
$(".editLink").click(function(){
//Code Here
});
The logic for the click function will be to grab the data from the row and make an AJAX Post back to a controller action.
$.post(urlToAction, data, succuessFunction);
This will work perfectly for you, however you will have to do a lot of the data insert, update, delete operations manually. There are some pretty handy JS frameworks out there like Knockout JS which will handle this automatically for you after a little wiring/plumbing work up front.
I suggest you check those out.
Hi i'm building application in MVC and i want to use a display template to display my model in a view. This is my template, but it gives me error when I try to display it:
#*<tr>
<td>#Html.Display(NameE)</td>
<td>#Html.Display(NameC)</td>
<td>#Html.Display(NameR)</td>
<td>#Html.Display(Timespan) </td>
<td><button class="button" type="submit" name="Review"></button></td>
</tr>*#
I want this template to display each row filled with database data in the td's, but it is doing nothing. What am I doing wrong ?
First, try using #Html.DisplayFor(yourModel, "YourTemplateName") in your view.
When you are doing default templates you should relate them to the model and put them in your Shared folder so it will relate to them. In your case you should do model related DisplayFor:
#model YourModel
<tr>
<td>#Html.DisplayFor(x => x.NameE)</td>
<td>#Html.DisplayFor(x => x.NameC)</td>
<td>#Html.DisplayFor(x => x.NameR)</td>
<td>#Html.DisplayFor(x => x.Timespan) </td>
<td><button class="button" type="submit" name="Review"></button></td>
</tr>
Then in your controller you should just use it like this:
#Html.DisplayFor(Model)
Take a look at this article for more information. Hope this helps ;]
Hey, I am new to asp and I would like to ask you for some help. I built store with MvcMusicStore tutorial help. Now I want to add a View to manage orders which will display just OrderID (in Index View), then more info in Details View. Info will come from table which looks like this:
When I list OrderID, its multiplying because each product creates new record with the same OrderID in the table. Is there any way to display each Id just once?
Then I tried to display more info in Detaild View but I failed again. I used this code in Controller:
public ActionResult Details(int id)
{
var orderdetail = storeDB.OrderDetails.Single(a => a.Order.OrderId == id);
return View(orderdetail);
}
but obviously it wont work because only one element can be displayed. I also tried with foreach loop in Details.aspx but I was getting some IEnumerables-related error. Any advice is welcome, sorry for newbie question and bad English. Thank you.
Edit: Here is Controller's code for Index View (Product in my table equals Album in tutorial):
public ActionResult Index()
{
var manageorders = storeDB.OrderDetails
.Include("Product").Include("Order")
.ToList();
return View(manageorders);
}
And Details View code:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/MasterPage.Master" Inherits="System.Web.Mvc.ViewPage<ss.Models.OrderDetail>" %>
Index
<div id="style3">manage orders</div>
<div id="style1">
<table>
<tr>
<th></th>
<th>
user
</th>
<th>
data
</th>
<th>
product
</th>
<th>
quantity
</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td>
<%: Html.ActionLink("Edit", "Edit", new { id=item.Order.OrderId }) %> |
<%: Html.ActionLink("Details", "Delete", new { id=item.Order.OrderId })%>
</td>
<td>
<%: item.Order.Username %>
</td>
<td>
<%: item.Order.OrderDate %>
</td>
<td>
<%: item.Quantity %>
</td>
<td>
<%: item.Quantity %>
</td>
</tr>
<% } %>
<p>
<%: Html.ActionLink("Create New", "Create") %>
</p>
And error I am recieving:
Compiler Error Message: CS1579: foreach statement cannot operate on variables of type 'ss.Models.OrderDetail' because 'ss.Models.OrderDetail' does not contain a public definition for 'GetEnumerator'
Single() will throw an exception if there's more than 1 element in the sequence, so the error here is because each Order can have many OrderDetails (this is your IEnumerable-ish error). If you wanted to select the first match, when there could be many, use the First() method, which won't throw if there's more than one.
It depends really what your controller is working with - Orders or OrderDetails. This would be the difference between Orders/Details/1 and OrderDetails/Details/1, where the first would be focussing on the whole order and all of its details, and the second would be looking at one specific line.
If you wanted to work with the order - which it looks like you're going for - then you'd need a reference of some kind from the Order to its collection of OrderDetails. If you're using something like Entity Framework like in the MusicStore tutorial, then you'll get this collection as part of your entity model. You would pass the Order to the view, and could then access the OrderDetails collection in a for each or similar loop e.g.
public ActionResult details(int id)
{
Order viewModel = storeDb.Orders.Single(o => o.Id = id);
return View(viewModel);
}
This wouldn't throw if Id is the unique per order, because there is only a single match (not many). Your view could then have something like:
<ul>
<% foreach (OrderDetails od in Model.OrderDetails) { %>
<li><%: od.UnitPrice %> (Or whatever information you wanted to show) </li>
<% } %>
</ul>
I'm assuming you would be using a strongly typed view of type Order, otherwise you'd have to work with ViewData, but it looks from your question like you're happy enough with those concepts already.
Edit - adding more...
1.The typing of your page is causing you some problems, make sure you are clear in your own mind exactly what your Model is. If you are passing in a list - like you would in an Index action - you need a page that inherits ViewPage> (you can see this in the <%# Page %> declaration at the top of the page). If you're going to write code like "for each... in model", that would imply that your model must contain more than one thing. This is where your "GetEnumerator" error message is from.
Your view as posted inherits ViewPage, i.e. the model is a single object, not a collection of objects, and so "for each ... in model" has no sensible meaning. The type of your View should be the same as the type being passed down by your controller. Your Index method passes a List, and List is an example of an IEnumerable. Your details however passes a single YourModelClass.
2.The error message "Compiler Error Message: CS1061: 'ss.Models.OrderDetail' does not contain a definition for 'OrderDetails'" - check your model, if there are relationships (foreign keys etc) between your tables, they should be joined on the model diagram, and you'd normally have navigation properties as well. The fact that you're getting this message means that something in that isn't there.
3.I'd suggest it might be worth checking out some of the videos, as the explanations are quite handy. Try some of the videos at http://www.asp.net/mvc/fundamentals . I Joe Stagner's "For the rest of us" series are very good, and as a starting point Stephen Walther's "Creating a Movie DB Application" would help, as it shows this kind of thing.
I'm new to MVC.
In the tutorials I've gone through they say it is good practise to have your entities object disposed of after it is passed to the view. Like so...
using(MyProjectEntities db = new MyProjectEntities)
{
return View(db.PersonAddresses.ToList());
}
However I don't want to just display the IDs of the Person and the Address records that are linked in the PersonAddress table. I want the whole shebang and I get an error when I do the following in my view.
<% foreach (var item in Model) { %>
<tr>
<td>
<%: item.Person.LastName + ", " + item.Person.FirstName %>
</td>
<td>
<%: item.Address.AddressLine1+ "<br />" + item.Address.AddressLine2 %>
</td>
<td>
<%: item.Room.RoomName %>
</td>
<td>
<%: String.Format("{0:g}", item.Date) %>
</td>
</tr>
<% } %>
However if do
MyProjectEntities db = new MyProjectEntities;
return View(db.PersonAddresses.ToList());
My view works fine.
Is there a better way of passing those values to the view where I can dispose of the Entities object properly?
One way is to "eager" load the data by adding .Include in your LINQ query, this pre-loads the specified data so it is ready to go.
It's better not to access your data layer directly from your controllers. I would create a separate business logic layer or service layer, and call that from the controllers, instead of calling the data access layer from your controllers. So your data access layer is not directly accessed by your user interface layer. This issue would then be moot.