I am doing web application where i have one table. i am making row data as html table header based on id.
This is what i tried. This is controller code.
public ActionResult Index()
{
var table = new List<test> {
new test { Label = "DocumentNumber", Value = "12345678", Emp_id = 1, Name = "First" },
new test { Label = "ExpiryDate", Value = "1/1/2015", Emp_id = 1, Name = "First" },
new test { Label = "DocumentNumber", Value = "123", Emp_id = 2, Name = "Second" },
new test { Label = "ExpiryDate", Value = "1/1/20244", Emp_id = 2, Name = "Second" }
};
var items = table.Where(x => x.Emp_id == 1 || x.Emp_id == 2).ToList();
var headers = items.Select(x => x.Label).Distinct().ToList();
var employers = items.Select(x => x.Emp_id).Distinct().ToList();
if(employers.Count > 1)
headers.Insert(0, "Name");
var data = new List<List<string>>();
data.Add(headers);
foreach (var emp in employers)
{
var row = new List<string>();
foreach (var header in headers)
{
if (header != "Name")
{
var cell = items.Where(x => x.Label == header && x.Emp_id == emp).FirstOrDefault();
row.Add(cell == null ? "" : cell.Value);
}
else
row.Add(items.Where(x => x.Emp_id == emp).First().Name);
}
data.Add(row);
}
return View(data);
}
This is view code
#model List<List<string>>
<table>
<thead>
<tr>
#foreach (var header in Model.First())
{
<th>#header</th>
}
</tr>
</thead>
<tbody>
#foreach (var row in Model.Skip(1))
{
<tr>
#foreach (var cell in row)
{
<td>#cell</td>
}
</tr>
}
</tbody>
</table>
Now i am able to render as below.
Name DocumentNumber ExpiryDate
First 12345678 1/1/2015
Second 123 1/1/20244
But i want header to be appeared for each row of data. For example if i add one more header Issueddate for Emp_id 2(i hardcoded at the begining) the output should look like below.
Name DocumentNumber ExpiryDate
First 12345678 1/1/2015
Name DocumentNumber ExpiryDate Issueddate
Second 123 1/1/20244 1/1/2015
So in the above code where i should make changes to appear headers for each row of data? Hope you clearly understood the scenario. Thanks in advance. i tried as you said but header appends to each row of data as below.
Name DocumentNumber ExpiryDate Issueddate
First 12345678 1/1/2015
Name DocumentNumber ExpiryDate Issueddate
Second 123 1/1/20244 1/1/2015
now issued date should come for only emp_id with 2? Hope you understood.
This is my code.
var table = new List<test> {
new test { Label = "DocumentNumber", Value = "12345678", Emp_id = 1, Name = "First" },
new test { Label = "ExpiryDate", Value = "1/1/2015", Emp_id = 1, Name = "First" },
new test { Label = "DocumentNumber", Value = "123", Emp_id = 2, Name = "Second" },
new test { Label = "ExpiryDate", Value = "1/1/20244", Emp_id = 2, Name = "Second" },
new test { Label = "Issuedon", Value = "1/1/20244", Emp_id = 2, Name = "Second" }
With respect to above data i want output like this below.
Name DocumentNumber ExpiryDate
First 12345678 1/1/2015
Name DocumentNumber ExpiryDate Issueddon
Second 123 1/1/20244 1/1/20244
Move the first loop to inside the second loop
<table>
<tbody>
<tr>
#for (int i = 1; i < Model.Count; i++)
{
foreach (var header in Model.First())
{
if (header == "Issuedon")
{
if (!string.IsNullOrEmpty(Model[i][3])) //assuming issue date will be at 3rd index , thoug this approch is not good as OP send model as List of string not model which is a ideal option
{
<th>#header
</th>
}
else
{
continue;
}
}
else
{
<th>#header
</th>
}
}
<tr>
#foreach (var cell in Model[i])
{
<td>#cell
</td>
}
</tr>
}
</tr>
</tbody>
SIDE NOTE : assuming issue date will be at 3rd index , though this approach is not good But there is no other option as OP send model as List of string not model which should be an ideal option
Related
I've got two ViewBag there and I would like to make one
in that way I can get the 2 different address of the customer shown in one DropDownList
....
var customerAdress = from cl2 in dc.Adresses
where cl2.Customer.User.UserEmail == User.Identity.Name
select cl2;
var Adresses = new SelectList(customerAdress.ToList(), "AdressID", "AdressLine1 ", null);
var Adresses2 = new SelectList(customerAdress.ToList(), "AdressID", "AdressLine2", null);
....
there is my View:
....
<tr>
<td>Address</td>
<td colspan="3">
#Html.DropDownList("Adresses", (IEnumerable<SelectListItem>)(ViewBag.Adresses))
</td>
</tr>
.....
You would need to concatenate them to be shown in one dropdown list like:
var addressesList = customerAdress
Select(x=> new
{
ID = x.AddressID,
AddressLine = x.AddressLine1 + x.AddressLine2
});
ViewBag.Adresses = new SelectList(addressesList.ToList() , "AdressID", "AddressLine ", null);
and do not set the DropDownList helper name same as your ViewBag key, they should be different to prevent unexpected behaviors.
And in view do like:
#Html.DropDownList("SelectAddress",ViewBag.Adresses as SelectList,"Select Address")
When you set the name of the DropDownList helper to be the same as ViewBag key it will look for a key in the ViewBag for populating the DropDownList items, in that case you would need to just specify name to be same as ViewBag key:
Html.DropDownList("Adresses","Select Address")
Hope it helps!
my question wasn't clear it contained already a try of solution which may have mislead all the solution i've got
so here my solution i just used Group property on SelectListItem
my controller
....
var customerAdress = from cl2 in dc.Adresses
where cl2.Customer.User.UserEmail == User.Identity.Name
where cl2.Commands.FirstOrDefault().DeliveryAdressID==cl2.AdressID
select cl2;
var addressesList = customerAdress.
Select(x => new
{
ID = x.AdressID,
AddressLine = x.AdressLine1
});
var addressesList2 = customerAdress.
Select (x => new
{
ID = x.AdressID,
AddressLine = x.AdressLine2
}) ;
var allAdress = new List<SelectListItem>();
var group1 = new SelectListGroup() { Name = "DeliverableAdress" };
foreach (var item in addressesList)
{
allAdress.Add(new SelectListItem() { Text = item.AddressLine, Group = group1 });
}
foreach (var item in addressesList2)
{
allAdress.Add(new SelectListItem() { Text = item.AddressLine, Group = group1 });
}
//var Adresses = new SelectList(addressesList.ToList(), "AdressID", "AddressLine ", null);
ViewBag.allAdress = allAdress;
....
and my view
....
<tr>
<td>Address</td>
<td colspan="3">
#Html.DropDownList("allAdress", (IEnumerable<SelectListItem>)ViewBag.allAdress)
</td>
</tr>
....
but actually i misunderstood it the right idea is t concatenate the 2 adresslines because it's just details of one address and no 2 address as i thought
I working with MVC 5/ EF 6. I have been trying to create a view that displays a calendar for multiple people.
I already have the view grouped by person, and I show a list of all dates within the search range. But if the person has nothing scheduled for that date, the date is not being listed under the person.
Right now, the empty dates with no one scheduled for anything are being grouped together under an "empty" person group.
My current results:
Person:
-------------------------------
04/01/16 (blank)
04/02/16 (blank)
04/03/16 (blank)
Person: Jane
-------------------------------
04/04/2016: To Do Item
04/05/2016: To Do Item
Person: John
-------------------------------
04/04/2016: To Do Item
04/05/2016: To Do Item
How can I get this result?
Person: Jane
-------------------------------
04/01/16 (blank)
04/02/16 (blank)
04/03/16 (blank)
04/04/2016: To Do Item
04/05/2016: To Do Item
Person: John
-------------------------------
04/01/16 (blank)
04/02/16 (blank)
04/03/16 (blank)
04/04/2016: To Do Item
04/05/2016: To Do Item
Query returned to view
var activecal = db.Calendar.Where(x => (x.CalDate >= startdate && x.CalDate <= enddate).ToList();
// merge calendar with date range in search selected
var calendar = (from d in dateRange //dateRange = date range search
join c in activecal.ToList() on d equals c.CalDate into joinedResult
from r in joinedResult.DefaultIfEmpty()
select new CalVM
{
FullName = r == null ? null : r.FullName,
CalLocation = r == null ? null : r.CalLocation,
calDay = d.Date,
}).ToList();
View
#{
foreach (var group in Model.GroupBy(a => a.FullName))
{
<h3>Person: #group.Key</h3>
<div class="table-responsive">
<table class="table table-hover small">
<tr>
<th>
Cal Day
</th>
<th>
Location
</th>
</tr>
#foreach (var i in group)
{
<tr>
<td>
#Html.DisplayFor(modelItem => i.calDay)
</td>
<td>
#Html.DisplayFor(modelItem => i.CalLocation)
</td>
</tr>
}
</table>
</div>
}
}
I understand that I have to somehow get the Person's name associated with all the dates in the dateRange list, I am just not sure how to do it. The only parameter in the date range list is a date, so there is nothing to join on.
You could GroupBy the person and then for each Date of your range you would keep the Date and the scheduled events (I named it ToDo) for that date. And I guess you can have more than one ToDo per date.
Example:
var dateRange = GetDateRange(new DateTime(2016, 1, 1), new DateTime(2016, 1, 5)).ToList();
var todos = new List<ToDo>
{
new ToDo { Date = new DateTime(2016,1,3), Person = "John", What = "Do that"},
new ToDo { Date = new DateTime(2016,1,4), Person = "John", What = "Do this"},
new ToDo { Date = new DateTime(2016,1,4), Person = "John", What = "Do nothing"},
new ToDo { Date = new DateTime(2016,1,2), Person = "Jane",What = "Do something"},
new ToDo { Date = new DateTime(2016,1,3), Person = "Jane", What = "Do whatever"}
};
var personToDos = todos.GroupBy(x => x.Person)
.ToDictionary(key => key.Key, value => dateRange.Select(date => new ToDosPerDate
{
Date = date,
ToDos = value.Where(a => a.Date == date)
}));
foreach (var item in personToDos)
{
Console.WriteLine(item.Key);
Console.WriteLine("---------------");
foreach (var model in item.Value)
{
Console.Write(model.Date + " ");
Console.WriteLine(string.Join(", ", model.ToDos));
}
Console.WriteLine();
}
And the other stuff:
public class ToDo
{
public DateTime Date { get; set; }
public string Person { get; set; }
public string What { get; set; }
public override string ToString()
{
return What;
}
}
public class ToDosPerDate
{
public DateTime Date { get; set; }
public IEnumerable<ToDo> ToDos { get; set; }
}
// From: http://stackoverflow.com/questions/3738748/create-an-array-or-list-of-all-dates-between-two-dates
public static IEnumerable<DateTime> GetDateRange(DateTime startDate, DateTime endDate)
{
if (endDate < startDate)
throw new ArgumentException("endDate must be greater than or equal to startDate");
while (startDate <= endDate)
{
yield return startDate;
startDate = startDate.AddDays(1);
}
}
The output of the above code is:
John
---------------
2016-01-01 12:00:00 AM
2016-01-02 12:00:00 AM
2016-01-03 12:00:00 AM Do that
2016-01-04 12:00:00 AM Do this, Do nothing
2016-01-05 12:00:00 AM
Jane
---------------
2016-01-01 12:00:00 AM
2016-01-02 12:00:00 AM Do something
2016-01-03 12:00:00 AM Do whatever
2016-01-04 12:00:00 AM
2016-01-05 12:00:00 AM
Sample to output personToDos in a MVC Razor view:
#model Dictionary<string, IEnumerable<ToDosPerDate>>
...
#foreach (var person in Model)
{
<h3>#person.Key</h3>
foreach (var d in person.Value)
{
<div>Date: #d.Date</div>
foreach (var todo in d.ToDos)
{
<div>#todo.What</div>
}
}
}
I have a list of Deviation items getting from database. The list contains Severity which may be null. Thats why I made the SeverityNotNull property to transform null values to -1. BTW Severity can be 0-3.
I would like to show Deviations items in which each Severity should be a DropdownList line by line. And of course in the DropdownList the appropriate item should be selected.
my ViewModel is:
[MetadataType(typeof(DeviationMetaData))]
public partial class Deviation {
public int SeverityNotNull {
get { return Severity == null ? -1 : Severity.Value; }
}
...
}
public class DeviationMetaData {
public Nullable<int> Severity { get; set; }
...
}
public class DeviationViewModel {
public Deviation Dev { set; get; }
public IEnumerable<Deviation> Deviations {
get {
DeviationRepository dm = new DeviationRepository();
return dm.GetAll;
}
}
public DeviationViewModel() {
WindowsIdentity current = WindowsIdentity.GetCurrent();
string name = current.Name.Split(new[] { '\\' })[1];
Dev = new Deviation { CreatedBy = name, CreatedDate = DateTime.Now };
}
}
my Controller is:
public ActionResult Index() {
IList<SelectListItem> items = new List<SelectListItem> {
new SelectListItem{Text = "", Value = "-1"},
new SelectListItem{Text = "Minor", Value = "1"},
new SelectListItem{Text = "Major", Value = "2"},
new SelectListItem{Text = "Critical", Value = "3"}
};
ViewBag.SelectSeverity = new SelectList(items, "Value", "Text");
return View( new DeviationViewModel() );
}
my View is:
#model DeviationViewModel
#using (Html.BeginForm()) {
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.Dev.Severity)
</th>
</tr>
#foreach (var item in Model.Deviations) {
<tr>
<td>
#Html.DropDownListFor(modelItem => item.SeverityNotNull, (SelectList)ViewBag.SelectSeverity)
</td>
</tr>
}
</table>
</fieldset>
}
</div>
I checked the SeverityNotNull values and they are correct. In the result there are the Dropdownlists, but nothing is selected. That is the problem. Could you give me some idea? Thanks.
It is not necessary to create a SeverityNotNull property. A SelectList can contain an option with a null value that if selected will post back null. You have multiple other problems as well including using a foreach loop that will render <selects> with duplicate name attributes (wont bind on postback) and duplicate id attributes (invalid html).
Start by creating a view model to represent a Deviation
public class DeviationVM
{
public int ID { get; set; }
public int? Severity { get; set; }
// other properties of the Deviation data model that you want to edit/display
}
Controller
public ActionResult Index()
{
// Get your deviations and map to the view model
List<DeviationVM> model = dm.GetAll().Select(d => new DeviationVM
{
ID = d.ID,
Severity = d.Severity
}).ToList();
// create your select list (
var severityList = new[] { new { ID = 1, Name = "Minor" }, new { ID = 2, Name = "Major" }, new { ID = 2, Name = "Critical" } };
ViewBag.SeverityList = new SelectList(severityList, "ID", "Name");
return View(model)
}
public ActionResult(List<DeviationVM> model)
{
...
}
View
#model List<DeviationVM>
#using (Html.BeginForm()) {
....
for(int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(m => m[i].ID)
#Html.DropDownListFor(m => m[i].Severity, (SelectList)ViewBag.SeverityList, "Text for null value")
}
Note the use of the for loop which generates <select name="[0].Severity" ..> <select name="[1].Severity" ..> which are correctly named with indexers and will be bound on post back. Note also the use of the overload of #Html.DropDownListFor() which will generate the options as <option value>Text for null value</option> <option value="1">Minor</option> .... The first option does not have a value so if it is selected the value of property Severity will be null on postback.
Note also that if the value of property Severity is initiallt null then the first option will be selected by default. If the value is 2, then the 3rd option will be selected by default.
I am trying to get the selected value of a dropdownlist in #Html.ActionLink but no luck so far. Requirement is to dynamically retrieve a table and have a dropdown list for actions that can be taken against the row. I need to select an action and then on hitting submit button, row ID and selected action value should be posted to the controller. Here is the piece of code I have in place.
#foreach (AdsViewModel ad in Model)
{
<tbody>
<tr>
<td>#ad.Row_Id</td>
<td class=" "> #ad.Description </td>
<td class=" "> #ad.Valid_To.ToShortDateString() </td>
<td><span class="label label-sm label-success label-mini"> #ad.Status </span></td>
<td>#Html.DropDownList("actions", ad.Actions) </td>
<td>#Html.ActionLink("Submit", "AdAction", new {adId = ad.Row_Id, action = ad.Actions.SelectedValue}) </td>
</tr>
</tbody>
}
On clicking the Submit ActionLink, I am getting the adId but no action is returned from the dropdownlist.
Your help is much appreciated.
Edit: Here is the AdsViewModel
public class AdsViewModel
{
public string Row_Id { get; set; } //Transaction Number
public string Description { get; set; } //Trasaction Description
public DateTime Valid_To { get; set; } //Expiry
public string Status { get; set; } //Object Status Code
public SelectList Actions { get; set; }
}
This is how the Select list is filled in Controller
List<SelectListItem> items = new List<SelectListItem>();
items.Add(new SelectListItem() { Text = "View", Value = "001" });
items.Add(new SelectListItem(){Text = "Modify", Value = "002"});
model.Actions = items;
This line
<td>#Html.ActionLink("Submit", "AdAction", new {adId = ad.Row_Id, action = ad.Actions.SelectedValue}) </td>
is setting the route value action to the selected value at the time the view is created on the server and before its sent to the browser (the user hasn't selected anything yet so its null). If you are wanting to set the value to "001" or "002" (the values of the dropdowns), then you need to use javascript update the href attribute of the link when the dropdown changes. An easier and more conventional solution would be to delete the dropdown and use 2 action links, one for Viewand one for Edit. Since they are 2 different actions, there should also be 2 seperate ActionResult methods in your controller. For example
#Html.ActionLink("View", "View", new { id = ad.Row_Id }) // calls the View method
#Html.ActionLink("Modify", "Modify", new { id = ad.Row_Id }) // calls the Modify method
Edit
To do this using javascript, delete the #Html.ActionLink and replace with a <button type="button"> or other element and handle its click event
var url = '#Url.Action("AdAction")';
$('button').click(function() {
var row = $(this).closest('tr');
var rowID = row.children('td').eq(0).text();
var actionID = row.find('select').val();
window.location.href = url + '?adId=' + rowID + '&action=' + actionID;
});
Note: You are creating invalid html with the #Html.DropDownList() method (all <selects> will have id="action")
This should fix it...
#for (int i = 0; i < Model.Count(); i++)
{
var ad = Model[i];
<tbody>
<tr>
<td>#ad.Row_Id</td>
<td class=" "> #ad.Description </td>
<td class=" "> #ad.Valid_To.ToShortDateString() </td>
<td><span class="label label-sm label-success label-mini"> #ad.Status </span></td>
<td>#Html.DropDownListFor("actions", m => m[i].Actions) </td>
<td>#Html.ActionLink("Submit", "AdAction", new {adId = ad.Row_Id, action = ad.Actions.SelectedValue}) </td>
</tr>
</tbody>
}
Thank you Everyone, I solved it by writing a Javascript function and calling that function on the onClink Event of the button.
<script type="text/javascript" language="javascript">
function ShowEditData() {
var url = '#Url.Action("AdAction")';
var rows = document.getElementById("mytable").rows;
for (var i = 0, ceiling = rows.length; i < ceiling; i++) {
rows[i].onclick = function () {
debugger;
var Row_Id = this.cells[0].innerHTML;
var actionID = this.cells[4].childNodes[0].value;
window.location.href = url + '?row_id=' + Row_Id + '&action_id=' + actionID;
}
}
}
</script>
I am using hardcoded string values for dropdownlist to the view , and passing the selected value from database , where 0 = pending , 1 = complete and 3 = awaiting, below is the code for view and controller:
var paymentStatus = new[] { "Pending", "Complete", "AwaitingPayment" };
ViewData["StatusID"] = new SelectList(paymentStatus, "Value", "Text", booking.StatusID);
<tr><td>Status</td><td><%: Html.DropDownListFor(m => m.StatusID, ViewData["StatusID"] as SelectList)%></td></tr>
It comes up with the error :
DataBinding: 'System.String' does not contain a property with the name 'Value'.
The problem with your example is that you are passing a string array into the SelectList and then telling the SelectList to use the Value and Text properties (which a string does not have). You should probably create a class for this:
public class Status {
public int Id { get; set; }
public string Text { get; set; }
}
var statusTypes = new List<Status> {
new Status { Id = 1, Text = "Pending" },
new Status { Id = 2, Text = "Complete" },
new Status { Id = 3, Text = "AwaitingPayment" }
};
Better yet, create a repository for this data:
var statusTypes = statusRepository.GetStatusTypes();
Pass this into your SelectList:
SelectList statusList = new SelectList(statusTypes, "Id", "Text", booking.StatusID);
// return this in a ViewModel or use ViewData like you are now:
ViewData["Status"] = statusList;
return View(statusList);
Please use view models:
var paymentStatuses = new[]
{
new SelectListItem { Value = "0", Text = "Pending" },
new SelectListItem { Value = "1", Text = "Complete" },
new SelectListItem { Value = "3", Text = "AwaitingPayment" },
};
var model = new SomeViewModel
{
StatusID = booking.StatusID,
Statuses = new SelectList(paymentStatuses, "Value", "Text")
}
return View(model);
and then:
<tr>
<td>
Status
</td>
<td>
<%= Html.DropDownListFor(m => m.StatusID, Model.Statuses) %>
</td>
</tr>
or if you insist on this ViewData (I don't recommend it, especially as you already have a view model):
var paymentStatuses = new[]
{
new SelectListItem { Value = "0", Text = "Pending" },
new SelectListItem { Value = "1", Text = "Complete" },
new SelectListItem { Value = "3", Text = "AwaitingPayment" },
};
ViewData["Statuses"] = new SelectList(paymentStatuses, "Value", "Text");
var model = new SomeViewModel
{
StatusID = booking.StatusID
}
return View(model);
and in the view:
<tr>
<td>
Status
</td>
<td>
<%= Html.DropDownListFor(m => m.StatusID, ViewData["Statuses"] as SelectList) %>
</td>
</tr>
The error shows it is unable to Fine "Value" , you have to do something like
new SelectList(paymentStatus, booking.Status, "Text", booking.StatusID)
bookin.Status will be the any text property of booking. hope this help