Split string on MVC3 + razor view - linq-to-sql

I would like to get help and guide on how can i manipulate text/string that being called from MS-SQL Database. So here is my SettingController.cs partial code for index viewing:
public ActionResult Index()
{
var datacontext = new SGM_SIDDataContext();
var dataToView = from m in datacontext.SGMs
orderby m.Seq
select m;
return View(dataToView.ToList());
}
And This is my index.cshtml codes:
#model IEnumerable<MVC_Apps.Models.SGM>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
SID
</th>
<th>
Abbrev
</th>
<th>
Val
</th>
<th>
Seq
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.SID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Abbrev)
</td>
<td>
#Html.DisplayFor(modelItem => item.Val)
</td>
<td>
#Html.DisplayFor(modelItem => item.Seq)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.GID })
</td>
</tr>
}
</table>
So roughly I got a View. Now here is what i would like to do:
1) The data 'item.Val' on Index.cshtml view will be like this:
A,L,C,H
and sort of like that. But the might be line where the data only contain:
H or C or none(Null value)
But if the data contain more than one char like say it does set for K and L, the data in item.Val will look like this:
A,L
Which the data being separate by comma. So now i want to split that item.Val data and do if statement on it. Where I would like to check every data in item.Val if it contain K or L or C or H or all of them or none of them(Sorry if my english is bad). And I would like to view it as , if all the data contain H so in table view, the will be column named Hotel while if the data also have L so another column of Lounge will be display with a check button being checked.
the possible char in item.Val is:
A = Admin
L = Lounge
H = Hotel
C = Customer
Any help and ideas much appreciated. Thank you in advanced.
Update information:
Thanks Im starting to get what is it. What i really want to do is, when the item.Val does contain H(which is for hotel) then the view will have table column with header name Hotel and at the record it will have tick checkbox.
This is sample picture of table view: http://imagebin.org/152941
But then the Hotel, Admin and User information either it is tick or not is in item.Val
For example for Smith, the item.Val data look like this : C,
For example for Anna , the item.Val data look like this : H,C,
P.S : - the var conf line is a test code. Ignore it as I already delete it from my source. :)

Create a ViewModel similar to
public class MyViewModel
{
// items from your model
public int Id{get;get;}
public String Vals{get;set;} // A,L,C,H
...
...
public bool IsHotel
{
get
{
return Vals.Split(',').Contains("H");
}
}
public bool IsAdmin
{
get
{
return Vals.Split(',').Contains("A");
}
}
public bool IsCust
{
get
{
return Vals.Split(',').Contains("C");
}
}
}
In the controller action
public ActionResult Index()
{
var datacontext = new SGM_SIDDataContext();
var dataToView = from m in datacontext.SGMs
orderby m.Seq
select new MyViewModel()
{
// items from your datacontext
Id= m.SID,
//etc...
};
var conf = from m in datacontext.SGMs // what's the purpose of this query??
select m.Val;
return View(dataToView.ToList());
}
The View will need to be updated, so include columns for Hotel, Cust, Admin and any others you need. I would suggest that you keep it simple and don't try to create the HTML columns on the fly. If you want to do this, you probably will need to inspect all Vals in every object of your list first to determine what columns are needed. In the view
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.SID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Abbrev)
</td>
<td>
#(item.IsHotel? "Checked" : "")
</td>
<td>
#(item.IsAdmin? "Checked" : "")
</td>
<td>
#(item.IsCust? "Checked" : "")
</td>
<td>
#Html.DisplayFor(modelItem => item.Seq)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.GID })
</td>
</tr>
}

Related

ASP.NET Only edit the last item from every type

Hey I have a RoadRecord table. I have an SQL database for it. I display it on Index.html. In the RoadRecords there are date,LicencePlate, Type, Fuel, Mileage etc.., User can edit these RoadRecords. But here is the problem, how can I implement that user only can edit the newest record for each Licenceplate.
For example:
Date
LicencePlate
08.19
AAA-111
08.17
AAA-111
08.16
CCC-222
In this situation I should be able to edit only the 08.19 AAA-111, and the 08.16 CCC-222.
There is any way to implement it in code or in SQL?
Here is my table in .html
<tbody>
#foreach (var item in Model)
{
<tr class="click box-shadow" onclick="location.href = '#(Url.Action("Details", "RoadRecords", new { id = item.Id }))'">
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.LicencePlateNavigation.LicencePlate)
</td>
<td>
#Html.DisplayFor(modelItem => item.User.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Location)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mileage)
</td>
<td>
#Html.DisplayFor(modelItem => item.Fueling)
</td>
<td>
#Html.DisplayFor(modelItem => item.Note)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.Id">Szerkesztés</a> |
<!--<a asp-action="Details" asp-route-id="#item.Id">Részletek</a> | -->
<a asp-action="Delete" asp-route-id="#item.Id">Törlés</a>
</td>
</tr>
}
</tbody>
EDIT 1 - Did it in SQL Manager Studio
I got it in SQL Manager Studio, now, how can I implement it in EntityFramework, or in code?
SELECT * FROM [RoadRecord] WHERE [Date] IN ( SELECT MAX([Date]) FROM [RoadRecord] GROUP BY [LicencePlate]);
You can use this linq to select the newest datatime goupby LicencePlate
var result = _dbContext.RoadRecords.GroupBy(x => x.LicencePlate).Select(x=>x.Max(z=>z.Date)).ToList();
I write a simple demo here.
public class HomeController : Controller
{
private readonly ProductDbContext _dbContext;
public HomeController(ProductDbContext dbContext)
{
_dbContext = dbContext;
}
//...other code....
[HttpPost]
public IActionResult Index(RoadRecord model)
{
//select the newest datatime from database
var result = _dbContext.RoadRecords.GroupBy(x => x.LicencePlate).Select(x=>x.Max(z=>z.Date)).ToList();
if (!result.Contains(model.Date))
{
//if the record is not the newest one, The controller will not change the data and response the error message.
ModelState.AddModelError("","you can only change the newest record");
var listmodel = _dbContext.RoadRecords.ToList();
return View(listmodel);
}
else
{
//if the record is the newest one,the controller will update the data in db.
//.......
}
}
}
Then add
<div asp-validation-summary="All" class="text-danger"></div>
In your View, Once user update the uncorrest record, The view will show the error message.
Or you can use FluentValidation to custom your validation rules, But i think it will be more complex.

How can I assign unique anchor tags to each row to return to that row after a page reload in MVC?

I have a view that contains a table of items. In each row of the table, you have the option to click on a link to edit the item which takes you to a different page. I'm trying to make it so that once you finish editing the item and save your changes, it takes you back to the original view but at the same spot.
So, for example, if you had 300 rows in this table and were working with row 247. I click Edit, make some changes, and when I save I'd like to go back to row 247. Instead, I'm brought back to the top of the page after saving. I've seen some stuff for jquery, but isn't there something simple that can be done in razor with anchor tags?
My Code looks like this:
View
Index.cshtml
...
...
...
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.AID)
</th>
<th>
#Html.DisplayNameFor(model => model.Comment)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.AID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comment)
</td>
<td colspan="5" align="right">
<button type="button" class="btn btn-primary" onclick="location.href='#Url.Action("Edit", new {id = item.AID })'">Action Event</button>
</td>
</tr>
}
</table>
Controller
DatabaseController.cs
public ActionResult Index()
{
return View(db.ActionableEvents.ToList());
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ActionableEvents actionableEvents = db.ActionableEvents.Find(id);
if (actionableEvents == null)
{
return HttpNotFound();
}
return View(actionableEvents);
}
[HttpPost]
public ActionResult Edit([Bind(Include = "AID,Comment")] ActionableEvents actionableEvents)
{
if (ModelState.IsValid)
{
db.Entry(actionableEvents).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(actionableEvents);
}
Ideally, it would be nice in my HttpPost for the Edit to do something like:
return RedirectToAction("Index",idtag);
where idtag could be a route value that loads the page at the specific anchor tag. Something to the effect of "https://www.mywebsite.com/Home/Index#247".
The question is, how can I append the model.AID value to the anchor tag (or maybe just do something in my tag) in my for loop and then reference this in the controller?
Add an id attribute matching the item id to each row:
#foreach (var item in Model)
{
<tr id="#item.AID"> #* assuming AID is the item id (e.g. 247)*#
<td>
#Html.DisplayFor(modelItem => item.AID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comment)
</td>
<td colspan="5" align="right">
<button type="button" class="btn btn-primary" onclick="location.href='#Url.Action("Edit", new {id = item.AID })'">Action Event</button>
</td>
</tr>
}
Then in your controller set the anchor to the html row's id which should be the same as the item id:
return Redirect(Url.Action("Index") + "#" + idtag); // assuming idtag is the item id (e.g. 247)
The idtag anchor must match the table row (tr) id attribute to make the page jump to the row.

Razor table with two columns in mvc

this my controller:
public ActionResult Index(int PID = -1, int TID = -1, string DateT = "")
{
return View(barcodes);
}
in my view :
#model IEnumerable<barkod.Models.Barcode>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.barC)
</td>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
</tr>
}
It is okay, but I want the table information to be in two columns.
Just add the table tag around your foreach loop. If you want to have 4 columns you have to add a counter. Either use a for loop instead of foreach (depending on your model type) or add your own row counter.
#model IEnumerable<barkod.Models.Barcode>
#{ int counter = 0; }
<table>
<tr>
#foreach (var item in Model)
{
<td>
#Html.DisplayFor(modelItem => item.barC)
</td>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
#if (++counter % 2 == 0)
{
</tr><tr>
}
}
</tr>
</table>
Like this on every 2nd loop a new row is added. You will have to add some additional logic to handle the case when the number of items is not equal.

PagedList MVC to get data from db based on pagesize

i added PagedList in my project, i have a search view, which basically calls a function to get values from database, my Pagedlist is working fine, but i am not sure if this gets whole data from database or only based on pageSize. For example i have total 30 records, and i added pagesize as 10, so view will show 10 records at a time and 3 pages. Now this PagedList get all 30 values, or only get 10 first time, then if user click on page 2 it gets next 10 records.
Because lets say i have thousand records, so i dont want system to load all of them, i just want to load it according to pagesize , and when user click on second page it gets next records, hope my point is clear, below is my code:
View:
#model PagedList.IPagedList<BackendIntegration.Models.VendorAllTransactions>
#using PagedList.Mvc;
#if (Model != null)
{
<hr />
<div class="form-horizontal">
<table class="table">
<tr class="bg-primary">
<th>
#Html.DisplayName("Date")
</th>
<th>
#Html.DisplayName("Type")
</th>
<th>
#Html.DisplayName("Amount")
</th>
<th>
#Html.DisplayName("User Name")
</th>
<th>
#Html.DisplayName("Vendor Name")
</th>
<th>
#Html.DisplayName("POS ID")
</th>
</tr>
#foreach (var trans in Model)
{
<tr>
<td>
#Html.DisplayFor(model => trans.Date)
</td>
<td>
#Html.DisplayFor(model => trans.TypeDesc)
</td>
<td>
#Html.DisplayFor(model => trans.Amount)
</td>
<td>
#Html.DisplayFor(model => trans.UserName)
</td>
<td>
#Html.DisplayFor(model => trans.VendorName)
</td>
<td>
#Html.DisplayFor(model => trans.POS_ID)
</td>
</tr>
}
</table>
<br />
<div id='Paging' style="text-align: center">
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)
of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("VendorAllTransactions", new { page }))
</div>
</div>
}
Controller:
public ActionResult VendorAllTransactions(VendorAllTransactionView vw, int? page)
{
int pageSize = 10;
int pageIndex = 1;
pageIndex = page.HasValue ? Convert.ToInt32(page) : 1;
IPagedList<VendorAllTransactions> model = null;
try
{
model = sales.VendorAllTransactions(vw).ToPagedList(pageIndex, pageSize);
}
catch (Exception exp)
{
ModelState.AddModelError("", exp.Message);
}
return View(model);
}
sales.VendorAllTransactions(vw) this call a fucntion with query, which will return records. But this clearly returning all the records. Is Pagedlist get only required number of rows(pagesize) or it gets everything.???
Please advise.
Thanks

Logic inside table. for each loop for formatting

Is there a way I could limit the tds to 4 or any number in the following set up ..please see code below. Right now, its displaying all model items in one single row (as it should according to the code). If the items are a dozen, they are all displayed one single row.. I would like a way to display this four in each row instead of all in one row... (am I talking about table inside a table?) can this be done?
<table>
<tr>
#foreach (var item in Model)
{
<td>
#Html.DisplayFor(modelItem => item.fld1)
#Html.DisplayFor(modelItem => item.fld2)
</td>
}
</tr>
</table>
You could group them:
#{
var chunkSize = 4;
var groupedResult =
from i in Model.Select((value, index) => new { Value = value, Index = index })
group i.Value by i.Index / chunkSize into g
select g;
}
<table>
#foreach (var result in groupedResult)
{
<tr>
#foreach (var item in result)
{
<td>
#Html.DisplayFor(modelItem => item.fld1)
#Html.DisplayFor(modelItem => item.fld2)
</td>
}
</tr>
}
</table>
Obviously the fact that you need to do this means that your view model is not adapted to this view. So adapt it and perform this grouping inside your controller action. Then your view will become simple and readable and not resemble some spaghetti code.