Show data from SQL database in Gridview - c#

I want to show data in grid view using 3 tables in SQL database.
first I created Model
public class common
{
public Artist Artist { get; set; }
public Album Album { get; set; }
public Genre Genre { get; set; }
}
Then This is the Controller
public ActionResult Show1()
{
var query = from a in DB.Album
join b in DB.Artists
on a.ArtistId equals b.ArtistId
join c in DB.Genre
on a.GenreId equals c.GenreId
where (b.ArtistId == 2)
select new common { Album = a, Artist = b, Genre = c };
return View(query.ToList());
}
}
After that this is my View
#model IEnumerable<test1.Models.common>
#{
ViewBag.Title = "Show1";
}
<h2>Show1</h2>
<div>
#{
var grid = new WebGrid(Model, defaultSort:"Name");
}
#grid.GetHtml()
</div>
But it doesn't show any data?
How can I do it?

I think you need an editorTemplate for your common object model
or use a for sentence and populate an html table
for example...
<table summary="">
<thead>
<tr>
<th></th>
<th>
Account No.
</th>
<th>
Customer Name
</th>
<th class="SingleCheckBox">
Is Approved
</th>
<th class="SingleCheckBox">
Is Locked out
</th>
<th>
Last Login
</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Count(); ++i)
{
var item = Model[i];
bool isSelected = item.AccountNo == selectedAccountNo;
<tr>
<td>#Html.RadioButton("selectedUserName", item.UserName, isSelected, new { name = "selectedUserName" })</td>
<td>
#Html.DisplayFor(model => model[i].UserName)
#Html.HiddenFor(model => model[i].UserName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td class="SingleCheckBox">
#Html.CheckBoxFor(model => model[i].IsApproved)
</td>
<td class="SingleCheckBox">
#if (item.IsLockedOut)
{
#Html.CheckBoxFor(model => model[i].IsLockedOut);
}
else
{
#Html.CheckBoxFor(model => model[i].IsLockedOut);
}
</td>
<td class="last-child">
#(TimeZoneInfo.ConvertTime(DateTime.SpecifyKind(item.LastLoginDate, DateTimeKind.Utc), timeZoneInfo).ToString())
</td>
</tr>
}
</tbody>
</table>

I believe that the best answer to your question is yet another question: "Why a WebGrid?"
If you refer to the default functionality of a newly created MVC project, you will see that the Index.cshtml will use a table (as suggested in the answer provided by #hagensoft). It has been my experience that when items are properly scaffolded for an MVC project in Visual Studio I have had to do very little work to get the list of models to display nicely, even paginated if necessary.
To make better use of pagination, if that is what you are after, I have made great use of the PagedList.MVC package available through NuGet (https://www.nuget.org/packages/PagedList.Mvc/). There is plenty of documentation related to the functionality provided by PagedList, and PagedList, along with the table suggestion/default view behavior with new MVC projects in Visual Studio, works wonders along side of any sorting, searching, or similar functionality that you would like to provide within your app.
A fantastic tutorial that I refer to about Sorting, Filtering, and Paging can be found here: https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
If you are insistent about using a WebGrid/GridView, I would suggest perhaps moving the database call out of the controller and directly into the Razor view itself, or try sending back an ObervableCollection<>, not a List<>, of a dedicated ViewModel from the Controller.
The moral of the story here is to not venture far from the provided path. Try to use the tools that are given to you and follow the default format for MVC projects.

First Add Jquery in your view
<script src="../../Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
If you want to style Add Style
<style type="text/css">
.webGrid { margin: 4px; border-collapse: collapse; width: 500px; background-color:#FCFCFC;}
.header { background-color: #C1D4E6; font-weight: bold; color: #FFF; }
.webGrid th, .webGrid td { border: 1px solid #C0C0C0; padding: 5px; }
.alt { background-color: #E4E9F5; color: #000; }
.gridHead a:hover {text-decoration:underline;}
.description { width:auto}
.select{background-color: #389DF5}
</style>
Add Model in your view
#{
test1.Models.common Common = new test1.Models.common();
}
Add Code in your view
#{
var grid = new WebGrid(Model, canPage: true, rowsPerPage: 5, selectionFieldName: "selectedRow",ajaxUpdateContainerId: "gridContent");
grid.Pager(WebGridPagerModes.NextPrevious);}
<div id="gridContent">
#grid.GetHtml(tableStyle: "webGrid",
headerStyle: "header",
alternatingRowStyle: "alt",
selectedRowStyle: "select",
columns: grid.Columns(
grid.Column("Id", "Id"),
grid.Column("Name", "Name"),
grid.Column("Description", "Description"),
))
#if (grid.HasSelection)
{
common= (test1.Models.common)grid.Rows[grid.SelectedIndex].Value;
<b>Id</b> #common.Artist.Id<br />
<b>Name</b> #common.Album.Name<br />
<b>Description</b> #common.Album.Description<br />
}
</div>
Edit this section According to your Model details
#if (grid.HasSelection)
{
common= (test1.Models.common)grid.Rows[grid.SelectedIndex].Value;
<b>Id</b> #common.Artist.Id<br />
<b>Name</b> #common.Album.Name<br />
<b>Description</b> #common.Album.Description<br />
}

Because of your model it doesn't show anything. Webgrid doesn't know how to render your Artist or Album or Genre table model. You need to create new model with basic variables like string, int, decimal
public ActionResult Show1()
{
var query = from a in DB.Album
join b in DB.Artists
on a.ArtistId equals b.ArtistId
join c in DB.Genre
on a.GenreId equals c.GenreId
where (b.ArtistId == 2)
select new common { AlbumName = a.AlbumName, ArtistName = b.ArtistName, GenreName = c.GenreName /* ... other props */ };
return View(query.ToList());
}
public class common
{
public string ArtistName { get; set; }
public string AlbumName { get; set; }
public string GenreName { get; set; }
//you need to use basic variables like string, int, decimal...
}

Related

Save multiple rows simultaneously from the same form - dotnet core

I have a table that has one empty column into which user can enter a comment:
Table
-----
TbMapId | UniqueAdp | Dealership | Line
--------------------------------------------------------------------
1 | [Insert comment here] | Derby | abc123
2 | [Insert comment here] | Keighley | cda345
3 | [Insert comment here] | Manchester | 876ghj
There is a lot of data to comment on, I can't expect a user to open an 'Edit' page and type in a comment one by one. Instead I need user to be able to input a bunch of comments (say 20 at a time against 20 rows) and save them all at one click of submit button.
If you want to jump straight to working solution go to EDIT #2 & look at Rudi's accepted answer
View
<form asp-action="TbMapViewEdit">
<div class="col-lg-6">
<div class="row">
<input type="submit" value="Save" class="btn btn-primary" />
<div class="col-md-12">
<table class="table table-condensed table-bordered table-hover">
<thead>
<tr>
<td><b>TEMP ID</b></td>
<td><b>Map To</b></td>
<td><b>Accounts Code</b></td>
<td><b>Line</b></td>
<td><b>Map Result</b></td>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.TBMapBalancesList.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(Model => Model.TBMapBalancesList[i].TbMapId)
#Html.HiddenFor(Model => Model.TBMapBalancesList[i].TbMapId)
</td>
<td>#Html.EditorFor(Model => Model.TBMapBalancesList[i].UniqueAdp, new { #class = "control-label_DI" })</td>
<td>#Html.DisplayFor(Model => Model.TBMapBalancesList[i].AccountsCode)</td>
<td>#Html.DisplayFor(Model => Model.TBMapBalancesList[i].Line)</td>
<td>#Html.DisplayFor(Model => Model.TBMapBalancesList[i].MapResult)</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</form>
Model
I've learned today that I need to use List to be able to iterate through the lines in table by the use of #for loop (as shown above). before I was trying to use IEnumerable. So I added a definition to the model for public List<TBMapBalances> TBMapBalancesList { get; set; }
public class TbMapViewModel
{
public IEnumerable<ASPNET_Core_1_0.Models.TBMapBalances> TBMapBalances { get; set; }
public IEnumerable<ASPNET_Core_1_0.Models.TBMapUniqueADP> TBMapUniqueADP { get; set; }
public List<TBMapBalances> TBMapBalancesList { get; set; }
[...]
}
Controller:
Now this is where I need the help with, my code doesn't throw any errors at all. When I press Submit nothing happens:
[Authorize]
[HttpPost]
public async Task<IActionResult> TbMapViewEdit(TbMapViewModel tbMapViewModel)
{
if (ModelState.IsValid)
{
foreach (var TbListId in tbMapViewModel.TBMapBalancesList)
{
var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();
if (getCode != null)
{
getCode.TbMapId = TbListId.TbMapId;
}
}
try
{
_context.Update(tbMapViewModel.TBMapBalances);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
throw;
}
}
return RedirectToAction("TbMapView");
}
EDIT #1
Changes to View
<form asp-action="TbMapViewEdit">
<div class="col-lg-6">
<div class="row">
<input type="submit" value="Save" class="btn btn-primary" />
<div class="col-md-12">
<table class="table table-condensed table-bordered table-hover">
<thead>
<tr>
<td><b>TEMP ID</b></td>
<td><b>Map To</b></td>
<td><b>Accounts Code</b></td>
<td><b>Line</b></td>
<td><b>Map Result</b></td>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.TBMapBalances.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(Model => Model.TBMapBalances[i].TbMapId)
#Html.HiddenFor(Model => Model.TBMapBalances[i].TbMapId)
</td>
<td>#Html.EditorFor(Model => Model.TBMapBalances[i].UniqueAdp, new { #class = "control-label_DI" })</td>
<td>#Html.DisplayFor(Model => Model.TBMapBalances[i].AccountsCode)</td>
<td>#Html.DisplayFor(Model => Model.TBMapBalances[i].Line)</td>
<td>#Html.DisplayFor(Model => Model.TBMapBalances[i].MapResult)</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</form>
Changes to model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ASPNET_Core_1_0.Models.TbMapViewModels
{
public class TbMapViewModel
{
public IEnumerable<ASPNET_Core_1_0.Models.TBMapUniqueADP> TBMapUniqueADP { get; set; }
public List<TBMapBalances> TBMapBalances { get; set; }
[...]
}
}
Changes to Controller:
Now this is where I need the help with, my code doesn't throw any errors at all when at the current state - when I press Submit nothing happens and no data gets saved to the database.
however, when you uncomment line _context.Update(tbMapViewModel.TBMapBalances); I get an error that List is not part of any Model and is not found.
Also, below code is something I wrote trying to follow this SO post: update-multiple-records-at-once-in-asp-net-mvc - Initially I was trying to make it Async but I was getting even more errors and couldn't continue. I thought I am going to follow it as closely as possible in hope that it will get me a working starting point.
[Authorize]
[HttpPost]
public IActionResult TbMapViewEdit(TbMapViewModel tbMapViewModel)
{
if (ModelState.IsValid)
{
foreach (var TbListId in tbMapViewModel.TBMapBalances)
{
var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();
if (getCode != null)
{
getCode.TbMapId = TbListId.TbMapId;
}
}
// _context.Update(tbMapViewModel.TBMapBalances);
_context.SaveChanges();
}
return RedirectToAction("TbMapView");
}
EDIT #2 - A hero to the rescue - big thanks to #RudiVisser for help
First of all if any of you guys are - like me - stuck using .net core 1.0.0
make sure you upgrade to the latest version first (1.1.7 lts). Part of my grief was that I was an USER 1.0 and did not upgrade my installation as fixes and additions kept coming out. Don't be that guy, like I was...
All below is thanks to Rudi's help:
View
#using (Html.BeginForm("TbMapViewEdit", "TbMap"))
{
<div class="col-lg-6">
<div class="row">
<input type="submit" value="Save" class="btn btn-primary" />
<div class="col-md-12">
<table class="table table-condensed table-bordered table-hover">
<thead>
<tr>
<td><b>TEMP ID</b></td>
<td><b>Map To</b></td>
<td><b>Accounts Code</b></td>
<td><b>Line</b></td>
<td><b>Map Result</b></td>
</tr>
</thead>
<tbody>
#Html.EditorFor(m => m.TBMapBalances);
</tbody>
</table>
</div>
</div>
</div>
}
Put your "Method", "Controller" in (Html.BeginForm("TbMapViewEdit", "TbMap")) otherwise the form POST action will be set to the current location.
Model
Truncated for brevity. I have view model with List that I will be saving the data to and one other table just for displaying some info.
public class TbMapViewModel
{
public IEnumerable<ASPNET_Core_1_0.Models.TBMapUniqueADP> TBMapUniqueADP { get; set; }
public List<TBMapBalances> TBMapBalances { get; set; } = new List<TBMapBalances>();
[...]
}
Controller
[Authorize]
[HttpPost]
public IActionResult TbMapViewEdit(TbMapViewModel tbMapViewModel)
{
if (ModelState.IsValid)
{
foreach (var TbListId in tbMapViewModel.TBMapBalances)
{
var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();
if (getCode != null)
{
getCode.UniqueAdp = TbListId.UniqueAdp;
}
}
_context.SaveChanges();
}
return RedirectToAction("TbMapView");
}
Error that I was making here is that I was trying to replace the key with essentially the copy of itself (Find ID of 1 and set it to ID of 1) instead of picking up on the actual one field that I needed to edit which in my case was UniqueAdp.
Then came the new thing to me, which was Editor Template:
Editor Template
Create a folder called EditorTemplates in 'Shared' Folder under your 'Views' folder with the exact name of the model that you intend to edit. In my case the model was called TBMapBalances so I created a TBMapBalances.cshtml file inside the newly created folder, then pasted this (this was originally in my main view file):
#model ASPNET_Core_1_0.Models.TBMapBalances
<tr>
<td>
#Html.DisplayFor(Model => Model.TbMapId)
#Html.HiddenFor(Model => Model.TbMapId)
</td>
<td>#Html.EditorFor(Model => Model.UniqueAdp, new { #class = "control-label_DI" })</td>
<td>#Html.DisplayFor(Model => Model.AccountsCode)</td>
<td>#Html.DisplayFor(Model => Model.Line)</td>
<td>#Html.DisplayFor(Model => Model.MapResult)</td>
</tr>
By the way the new { #class = "control-label_DI" } is there to supposedly add class to each created input field. This doesn't seem to work in .net core and is left there just as a reminder to myself that I need to do this somehow.
Research:
Update multiple records at once in asp.net mvc
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms
http://www.binaryintellect.net/articles/b1e0b153-47f4-4b29-8583-958aa22d9284.aspx
How to bind an Array in MVC Core
https://www.red-gate.com/simple-talk/dotnet/asp-net/model-binding-asp-net-core/
ASP.NET Core 1.0 POST IEnumerable<T> to controller
This problem has 2 parts to it, the first is that there needed to be a way to edit collections of data. This can be solved with EditorTemplates, which involves creating a single editor model and then calling #Html.EditorFor(..) on the collection of items you wish to edit.
A minimal sample (Full Fx, not Core) is available on Github.
The second problem was with the way the entities were being updated, the property being changed was wrong and hence not saving (the PK was being updated to the PK) and the entity was being attached when it's already tracked.
foreach (var TbListId in tbMapViewModel.TBMapBalancesList)
{
var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();
if (getCode != null)
{
getCode.TbMapId = TbListId.TbMapId;
}
}
try
{
_context.Update(tbMapViewModel.TBMapBalances);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
throw;
}
It's important to remember what Entity Framework does for you when you retrieve a model from the database. It is automatically tracked by the context, and so it's already attached and ready to update, anything you change will be automatically tracked and subsequently saved.
The call to _context.Update(..) tries to attach the non-tracked models (from your POSTed data) to the context based on ID, but because you've already pulled that ID out (in your .Where(..).FirstOrDefault(..)) it's already tracked, and so blows up.
Also given that this is EFC 1.0 and you have no .Find(..) method, using .SingleOrDefault(..) is probably a better method to use on a primary key field.
Your rewritten code could be as so:
foreach (var postedModel in tbMapViewModel.TBMapBalancesList)
{
var dbModel = _context.TBMapBalances.SingleOrDefault(p => p.TbMapId == postedModel.TbMapId);
if (dbModel != null)
{
dbModel.UniqueAdp = postedModel.UniqueAdp;
}
}
await _context.SaveChangesAsync();
For posterity though I wouldn't recommend it for security reasons, if you wanted to attach your whole posted model to the context (based on ID) and update it, you can do so with code similar to your original, removing the foreach loop:
_context.UpdateRange(tbMapViewModel.TBMapBalances);
await _context.SaveChangesAsync();
(I don't recommend it because everything that was posted will then be set in the database, from experience it's advisable to only set the fields you're expecting to update as per the first code set. It should, however, be quicker than the foreach loop given that you're not loading from the database and saving back in, only the latter)
Do you have the inputs for the comments already built into the razor page? I do not see them. What you would want to do is create a form with the input types that you want for each item in the loop inside the loop. Each form would then reference the iterator as a hidden value to pass when posted. If the loop is foreach(var item in Model.items){} you would have a form containing the inputs in that block with a hidden input that looks like <input type="hidden" name="index" value="#item.index"/> This will allow you to post with whatever identifier you need to attach that specific form data to the correct model.
See this answer for the structure of the form inside the loop Multiple forms on one MVC form, created with a loop, only the first submits data

Change TextBox Value and Update On Ajax Call

I am working on an ecommerce site where I am stuck on the cart management. Basically before login, products are kept in a session and I am trying to update the product quantity stored in the session using Ajax. I mean whenever I write in the 'Quantity To Change', the changed value should be reflected in the 'Quantity' column.
Note: I've shortened the post and figured out why it wasn't firing while debugging. Actually I was unable to get the id of the associated product. Now it passes the id. That's it. Now I've another issue - The TextBox are being created dynamically with a for loop. I used developer tools to figure out how the TextBoxes are generated dynamically and it is something like this:
For Product 1: cartDetails_0__Quantity
For Product 2: cartDetails_1__Quantity
I am wondering how to grab the quantity or values from the dynamically generated TextBoxes. If I put the generated id from HTML directly to Ajax, then it updates the quantity. Otherwise it doesn't. I've tried to use a loop in Ajax but I think, I am getting it wrong. Please see the View.
The view:
<table border="1" width="100%" cellpadding="4">
<thead>
<tr>
<th style="text-align:center;">Name</th>
<th style="text-align:center;">Price</th>
<th style="text-align:center;">Quantity</th>
<th style="text-align:center;">Quantity To Change</th>
</tr>
</thead>
<tbody>
#if (ViewBag.CartDetails != null)
{
for (int i = 0; i < cartDetails.Count(); i++)
{
<tr>
<td style="text-align: center; display:none;">#Html.DisplayFor(model => cartDetails[i].ProductId)</td>
<td id="ID" style="text-align: center;">#Html.DisplayFor(model => cartDetails[i].ProductName)</td>
<td style="text-align: center;">#Html.DisplayFor(model => cartDetails[i].Price)</td>
<td style="text-align: center;">#Html.DisplayFor(model => cartDetails[i].Quantity, new { #class = "quantityUpdate" })</td>
<td style="text-align: center;">#Html.TextBoxFor(model => cartDetails[i].Quantity, new { #class = "quantity", data_id = cartDetails[i].ProductId } )</td>
</tr>
}
}
</tbody>
</table>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
var url = '#Url.Action("UpdateCart")';
$(".quantityUpdate").change(function () {
var id = $(this).data('id');
var i = 0;
$('.quantityUpdate').each(function (i, item) {
$.post(url, { id: id, Quantity: $("#cartDetails_"+i+"__Quantity").val() }, function (response) {
if (response) {
$("#TotalPrice").load(window.location + " #TotalPrice");
}
});
})
alert(id);
alert($("#cartDetails_"+i+"__Quantity").val());
});
Here is an image sample that I am trying:
$('.quantity').change(function(){
$('.quantityUpdate').val($('.quantity').val());
// put code here
});
Instant Change
$('.quantity').keyup(function(){
$('.quantityUpdate').val($('.quantity').val());
// put code here
});
If the idea is to call ajax when you change the value in .quality textbox then this is how you should do:
$('.quantity').change(function(){
//your ajax call
});

Display table rows based on condition

I'm developing an web app using C# and MVC. One of the page has multiple <tr> which will contain information but this information gets updated over time (1 month to 6 month) range. So I only want to show the <tr> which include the information. The information is stored in a database, each <tr> has it's own column. The approach I've gone with is I read the data and apply if conditions in the view.
So something like
#if (!string.IsNullOrEmpty(Model.SomePropertyOne))
{
<tr>
<td>#Html.DisplayNameFor(model => model.SomePropertyOne)</td>
<td>#Html.DisplayFor(model => model.SomePropertyOne)</td>
</tr>
}
#if (!string.IsNullOrEmpty(Model.SomePropertyTwo))
{
<tr>
<td>#Html.DisplayNameFor(model => model.SomePropertyTwo)</td>
<td>#Html.DisplayFor(model => model.SomePropertyTwo)</td>
</tr>
}
...
I have to this 8 times. So my question is, is there a better approach than this or am I stuck with using all these if statements?
Please let me know if you require any further information
You can create a DisplayTemplate containing the condition. In /Views/Shared/DisplayTemplates/ create a partial view (say) MyTemplate.cshtml
#model string
#if (!string.IsNullOrEmpty(Model))
{
<tr>
<td>#Html.DisplayNameFor(m => m)</td>
<td>#Model</td>
</tr>
}
and then in the view
#Html.DisplayFor(m => m.SomeProperty, "MyTemplate")
#Html.DisplayFor(m => m.AnotherProperty, "MyTemplate")
.... //etc
The DisplayFor() will generate the html based on the template, so if the value of the property is null or string.Empty, then nothing will be generated for that property.
Side note: You should not be using <table> elements for layout (refer Why not use tables for layout in HTML? and Why Tables Are Bad (For Layout*) Compared to Semantic HTML + CSS). Instead, use css to style you layout. For example, change the DisplayTemplate to
<div class="field">
<div class="field-label">#Html.DisplayNameFor(m => m)</div>
<div class="field-value">#Model</div>
</div>
and add the following css
.field {
position: relative;
margin: 5px 0;
}
.field-label {
position: absolute;
width: 240px;
color: #808080;
}
.field-value {
margin-left: 250px;
}
You can solve your problem via reflection, something like that:
#foreach(var prop in Model.GetType().GetProperties().Where(x => x.PropertyType == typeof(string)))
{
var value = prop.GetValue(Model);
if (value != null)
{
<tr>
<td>#prop.Name</td>
<td><input value="#value.ToString()" name="#prop.Name" /></td>
</tr>
}
}
But, at this case, you should avoid to use #Html helpers, instead - write corresponding html explicitly.

Sort DateTime object in DD/MM/YYYY format in .cshtml file

I currently have a for-loop in my .cshtml file which iterates through items inside a ViewBag. I want to sort these objects based on a DateTime property called orderDate in the Order.cs file. The for loop in the .cshtml file looks like the following:
<table id="order-history-table" class="table table-hover">
<thead>
<tr>
<th>
Order Number
</th>
<th>
Order Date
</th>
<th>
Order Total
</th>
</tr>
</thead>
<tbody>
#foreach (var item in ViewBag.list)
{
<tr>
<td>
<a class="orderNumber" data-toggle="modal" data-target="#modal-container" href="#Url.Action("orderDetails", "Orders", new { orderNumber = item.order.OrderNumber })">#item.order.OrderNumber</a>
<br />
#Html.ActionLink("Re-Order", "ReOrder", new { orderNumber = #item.order.OrderNumber }, new { onclick = "return confirm('Are you sure you wish to re-order?');" })
</td>
<td>#item.order.OrderDate.ToString("dd/MM/yyyy")</td>
<td style="text-align: center">$#(Math.Round(item.order.OrderTotal, 2))</td>
</tr>
}
</tbody>
I want this table to be sorted so that the most recent orders are shown at the top of the table. Since the data is being pulled from a database, and the tables values are generated dynamically, where do I perform this sorting? is it done through jQuery? How do I do this?
Thank you in advance
You can use LINQ OrderBy to do that.
So in your action method where you set the ViewBag.list, You can use OrderByDescending method on the collection.
var yourOrderList=new List<Order>();
// to do : Load Order items to yourOrderList
yourOrderList=yourOrderList.OrderByDescending(f=>f.OrderDate).ToList();
ViewBAg.list=yourOrderList;
I also recommend using a view model to pass data from your action method to view.
var yourOrderList=new List<Order>();
// to do : Add orders to yourOrderList
yourOrderList=yourOrderList.OrderByDescending(f=>f.OrderDate).ToList();
return View(yourOrderList);
And in your view
#model List<Order>
<h3>Orders</h3>
#foreach(var o in Model)
{
<p>#o.OrderDate.ToString()</p>
}
Since your view is strongly typed, you can do the same ordering in your razor view also as needed.
#model List<Order>
<h3>Orders</h3>
#foreach(var o in Model.OrderByDescending(g=>g.OrderDate))
{
<p>#o.OrderDate.ToString()</p>
}

Ajax.BeginForm Not working correctly in FireFox (Only submits Post once)

I am using Ajax.Begin form with a partial view to replace contents of defined target.
like so,
Partial View:
#model string
<fieldset style="width:916px">
<legend class="SearchFiledSet">AMN</legend>
<table>
<tr valign="top">
<td>Notes:&nbsp</td>
<td>#Html.TextArea("Notes", #Model, 5, 30, new { disabled = "disabled", style = "background: #FFF; border: 1px solid #000;" })</td>
#using (Ajax.BeginForm("AMN", new AjaxOptions { UpdateTargetId = "AMN",
Url = Url.Action("AMN"),
OnBegin = "OnBegin",
OnFailure = "OnFailure",
OnSuccess = "OnSuccess",
OnComplete = "OnComplete"}))
{
<td style="padding-left: 30px">P N: &nbsp #Html.TextBox("PN", "", new { size = "15" })
#if(string.IsNullOrEmpty(#Model))
{
<br />
<font color="red">No matching pn was found in the system.</font>
}
</td>
<td style="padding-left: 60px">
<button type = "submit">Search</button>
</td>
}
</tr>
</table>
</fieldset>
Controller:
public PartialViewResult AMN(string PN = null)
{
IPS p=null;
string remarks= " ";
if (PN != null)
{
p = _pS.GetPPN.Trim());
remarks = p != null ? p.Remarks : remarks;
}
return PartialView(((object)remarks));
}
Main View:
<div id="AMN" style="margin-left: 180px">
#Html.Action("AMN")
</div>
The Ajax calls work fine in IE of course, but in Firefox it hits the break point on the controller and correctly posts during the first submit but then nothing will happen after each consecutive submit. Not even the break point will get hit. I have seen a few other posts of people complaining of this same issue a few years ago but none of them had a resolution. Has anyone experienced this issue and found a resolution or have any recommendations of what can be the issue?
There is another Html.BeginForm on the main page that I link my partial view to, but my partial view is outside that form, and I also tried removing the other form and just leaving the ajax one with no luck.
I am using jquery-1.7.2
I think I now understand what is happening based off of general research on the topic rather than directing it to Ajax.BeginForm method. I wanted to basically mimic a the concept of a panel, and be able to just plug in the full form and replace the panel (partial view) with updated data on the ajax call. Well I am not that experienced with ajax or javascript, but it seems that when I rewrite the html the object on the dom is getting replaced too so all focus is lost, hence it worked on one post but not twice.
This was confusing mostly because it worked the way I originally thought it would on Internet Explorer but not Firefox. So in order to make it cross-browser compatible I just used JSON to send back the data to be changed and then registered a function to the OnSuccess call, which will just change the html necessary rather than rebuilding the partial. I wanted to handle the Ajax mostly with the Asp.net MVC framework libraries to keep the code cleaner but I guess this isn't likely to happen unless I abstract out the form contents from the partial.
Here is the changes made for anyone else who runs into this issue:
Controller:
[HttpGet]
public PartialViewResult AMN()
{
string remarks = " ";
return PartialView(((object)remarks));
}
[HttpPost]
public JsonResult AMN(string PN = null)
{
IPS p=null;
string remarks= " ";
if (PN != null)
{
p = _pS.GetP(PN.Trim());
remarks = p != null ? p.Remarks : null;
}
return Json(remarks);
}
PartialView:
#model string
<fieldset style="width:916px">
<legend class="SearchFiledSet">AMN</legend>
<table>
<tr valign="top">
<td>Notes:&nbsp</td>
<td>#Html.TextArea("Notes", #Model, 5, 30, new { disabled = "disabled", style = "background: #FFF; border: 1px solid #000;" })</td>
#using (Ajax.BeginForm("AMN", "PS", null, new AjaxOptions {OnSuccess = "processData" }, new { id = "AMNForm" }))
{
<td style="padding-left: 30px">PN: &nbsp #Html.TextBox("PN", "", new { size = "15" })
#if(string.IsNullOrEmpty(#Model))
{
<br />
<font color="red">No matching pn was found in the system.</font>
}
</td>
<td style="padding-left: 60px">
<button type = "submit">Search</button>
</td>
}
</tr>
</table>
</fieldset>
<s.. type="text/java..">
function processData(data) {
$("#Notes").val(data);
if (!data[0])
alert("data is null")
else
alert("data is not null")
}
</..>

Categories