I have a dropdownlist in edit view that has a value from the database. What I want to do is to display the saved value in separate dropdown list. For example, I have saved two different data in database with same foreign key to determine that these two records are treated as one. (See below sample image)
https://imgur.com/ex57YTO
I am only using single-selection dropdown list and I am only looping the count of records to determine how many dropdown list to display in the edit page. So if I have "No harm event" and "Complaints" events, this must be displayed in separate dropdown list because what I did now is they are both displaying in one dropdown list so the result is it looks like the record is duplicated (see image below) but actually these two records are in each of the dropdown list.
https://imgur.com/YlVZHWx
https://imgur.com/FXYO4Tn
VIEW
//for loop to count records that will determine how many dropdown list to be displayed
#for (var i = 0; i < Model.SavedEventsToList.Where(a => a.incidentReportId == Model.IRId).Count(); i++)
{
<tr>
<td style="border-bottom:none !important;border-top:none !important;">
<div class="input-group">
<select class="form-control pseEventDDLInEdit" id="pseEventListInEdit" name="pseAddedEvent">
#{
foreach (var item in Model.SavedEventsToList)
{
if (item.selected == "yes")
{
if (item.incidentReportId == Model.IRId) //this is the foreign key that determine these two records are as one
{
<option value=#item.pseEventsId selected>#item.pseEventsName</option>
}
}
else
{
<option value=#item.pseEventsId>#item.pseEventsName</option>
}
}
}
</select>
</div>
</td>
</tr>
}
CONTROLLER
public ActionResult Edit(Guid? id)
{
IMRBusinessLogic imrLogic = new IMRBusinessLogic();
var imrRepo = new IMRRepository();
IMRDTO imr = imrRepo.GetIRDetailsForEdit(id);
imr.SavedEventsToList = imrLogic.SavedEvents(id);
return View(imr);
}
public List<PSESavedEventsDTO> SavedEvents(Guid? incidentReportId)
{
using (IREntities db = new IREntities())
{
var events = (from a in db.SavedPatientSafetyEvents(incidentReportId)
select new PSESavedEventsDTO
{
pseSavedEventId = a.pse_saved_event_category_and_subcategory_id,
pseEventsId = a.pse_events_id,
pseEventsName = a.pse_events_name,
seqNum = a.seq_num,
incidentReportId = a.incident_report_id,
savedRowIndex = a.saved_row_index,
selected = a.selected
}).ToList();
return events;
}
}
I need to separate them so the user can still have an option to edit each of these two records.
This is the expected output I need: https://imgur.com/uwVjvkz
Can someone help me with this.
Thank you in advance.
I already found the solution in this. I just use foreach instead of for loop, and I get the desired output I need.
#foreach (var index in Model.SavedEventsToList.Where(a => a.savedRowIndex != 0))
{
<tr>
<td style="border-bottom:none !important;border-top:none !important;">
<div class="input-group">
<select class="form-control pseEventDDLInEdit" id="pseEventListInEdit" name="pseAddedEvent">
#{
foreach (var item in Model.SavedEventsToList)
{
if (item.selected == "yes")
{
if (item.incidentReportId == Model.IRId && item.savedRowIndex == index.savedRowIndex)
{
<option value=#item.pseEventsId selected>#item.pseEventsName</option>
}
}
else
{
<option value=#item.pseEventsId>#item.pseEventsName</option>
}
}
}
</select>
<span title="Patient Safety Events Description" class="input-group-addon" data-toggle="popover" data-container="body" data-placement="right" data-trigger="hover" data-html="true" href="#" id="login"><i class="fa fa-info-circle"></i></span>
</div>
</td>
</tr>
}
Related
I have a model with 34 numbered properties in it as shown below
Public Class ViewModel
{
public string RatingCategory01 { get; set; }
public string RatingCategory02 { get; set; }
public string RatingCategory03 { get; set; }
//...and so on until category #34
}
Rather than code an input for each category in Razor Pages, I would like to use a loop to iterate through all the categories and generate the appropriate control groups. I have tried the code below:
<tbody>
#for (var i = 1; i < 35; i++)
{
string n;
#if (i > 0 && i < 10)
{
n = "RatingCategory0" + i.ToString();
}
else
{
n = "RatingCateogry" + i.ToString();
}
<tr>
<td>
<label asp-for="#string.Format("RatingCategory" + n)" class="control-label"></label>
</td>
<td>
<select asp-for="#string.Format("RatingCategory" + n)" asp-items="Model.CategoryRatingSelectList">
<option value="">Select</option>
</select>
</td>
<td>
<input asp-for="#string.Format("RemedialTime" + n)" class="form-control" />
</td>
</tr>
}
</tbody>
When I build the project and navigate to the page, I get this error:
InvalidOperationException: Templates can be used only with field
access, property access, single-dimension array index, or
single-parameter custom indexer expressions.
I'm not sure if I am on the right track here. I would really like to create a loop to generate these inputs so make future maintenance and changes easier. It's probably pretty obvious from my code/question that I am pretty new to this, so any help is appreciated.
EDIT TO ADD SOLUTION:
I used the solution provided by Ed Plunkett which I have checked below. I altered it a bit and ended up creating a new class called 'Rating' because I found that in practice I needed a more complex object. Inside my view is now
public List<Rating> Ratings = { get; set; }
In the controller, I use a loop to add as many empty ratings as I need to the list depending on the number I need.
for (var i = 0; i < 34; i++)
{
vm.Ratings.Add(new Rating());
}
Though this will likely be updated to use something other than a hard-coded number as the application evolves.
Finally, I used a loop in the view to create a group of controls for every Rating in my List. In this case it is a TableRow containing different controls in different columns:
#for (var i = 0; i < Model.Ratings.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(model => model.Ratings[i].Category)
</td>
<td>
<div class="form-group">
<select asp-for="Ratings[i].RatingValue" asp-items="Model.CategoryRatingSelectList">
<option value="">Select</option>
</select>
</div>
</td>
<td>
<input asp-for="Ratings[i].RemediationMinutes" class="form-control" />
</td>
</tr>
}
I've found that the data in this group of inputs can be bound as a List by simply including
List<Rating> Ratings
in the parameters on whichever method runs when the form is submitted.
This is what you want instead of those 34 properties and their implied 34 RemedialTime siblings:
public List<String> RatingCategory { get; set; } = new List<String>();
public List<String> RemedialTime { get; set; } = new List<String>();
If you have 34 of something and the names differ only by an index number, that's a collection, not 34 distinct properties with sequentially numbered names. Then you can enumerate the 34 items with a foreach loop, or index them individually as RatingCategory[0] through RatingCategory[33]. In C#, collection indexes start at zero, so the first one is 0 and the thirty-fourth one is 33. You get used to it.
You should also look up what String.Format() does. String.Format("Foo" + 1) is exactly the same as "Foo" + 1.
You could convert your model class to dictionary;
var viewModel = new ViewModel()
{
RatingCategory01 = "a",
RatingCategory02 = "b",
RatingCategory03 = "c"
};
var dictionaryModel = viewModel.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(viewModel, null));
Then you can iterate the dictionary in the view.
I have a static property like following:
public static List<string> _pr { get; set; }
Let's imagine a scenario like this:
User 1 logs in and fills the _pr property with 100 string items inside _pr;
User 2 logs in at the same time and does the exact same thing as User one, only this time he gets 250 different string results into _pr!
These results are not from DB, but rather from an API;
How do I ensure the integrity and uniqueness of data so that each user gets displayed only the results that he gets, since I declared only 1 static property and I have multiple users adding different items into it...
Can you guys help me out with this?
How would I solve this properly in c#?
Edit: This is how I add the items to the specific list:
foreach (var item in _pr)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(item);
ResultItem rezultat = new ResultItem();
ViewBag.jsonobjekat = JObject.Parse(JsonConvert.SerializeXmlNode(doc));
rezultat.SaleNumber = ViewBag.jsonobjekat["GetItemTransactionsResponse"]["ReturnedTransactionCountActual"];
rezultat.StoreName = ViewBag.jsonobjekat["GetItemTransactionsResponse"]["Item"]["Seller"]["UserID"];
rezultat.Feedback = ViewBag.jsonobjekat["GetItemTransactionsResponse"]["Item"]["Seller"]["FeedbackScore"];
rezultat.SaleEarning = Convert.ToDouble(ViewBag.jsonobjekat["GetItemTransactionsResponse"]["Item"]["SellingStatus"]["CurrentPrice"]["#text"]) * Convert.ToInt32(rezultat.SaleNumber);
rezultat.SalePrice = Convert.ToDouble(ViewBag.jsonobjekat["GetItemTransactionsResponse"]["Item"]["SellingStatus"]["CurrentPrice"]["#text"]);
rezultat.Title = ViewBag.jsonobjekat["GetItemTransactionsResponse"]["Item"]["Title"];
rezultat.URL = ViewBag.jsonobjekat["GetItemTransactionsResponse"]["Item"]["viewItemURL"];
rezultat.ID = ViewBag.jsonobjekat["GetItemTransactionsResponse"]["Item"]["ItemID"];
lista.Add(rezultat);
ViewBag.jsonba = ViewBag.jsonobjekat;
}
JArray v = JArray.Parse(JsonConvert.SerializeObject(lista).ToString());
ViewBag.rezultati = v; // this is the part where I need to have unique results for each user
And this is how I display the results :
<tbody>
#foreach (var item in ViewBag.rezultati)
{
<tr>
<td>#item.StoreName</td>
<td><button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="top" title="" value="#item.StoreName" data-original-title="Analyze competitor"><i class="fa fa-bar-chart-o"></i></button></td>
<td>
<b>
#item.SaleNumber
</b>
</td>
<td><b>#item.Feedback</b></td>
</tr>
}
</tbody>
I need to display results based on user selection from a drop down menu. The menu itself is dynamically populated with "jobquery".
I wrote the following code:
#{
var db = Database.Open("database");
String jobquery = "select description from match_jobs";
IEnumerable<dynamic> data = null;
var grid = new WebGrid(data, canPage: false);
if(IsPost)
{
var description = Request["job"];
String sql = "select top 30 * from match_#0_output";
data = db.Query(sql, description);
}
}
Then in html, I have
<div id="dynamic">
Select Job
<form name = "search" method="post">
<select name="job">
<option value="" selected disabled>Select Job</option>
#foreach (var row in db.Query(jobquery))
{
<option value="#Request["job"]">#row.description</option>
}
</select>
<input type="submit" value="#Request["job"]"/>
</form>
</div>
The drop down menu worked fine. However, I am unable to call
#grid.GetHtml(); -> A data source must be bound before this operation can be performed.
I tried
</tr>
#foreach (var row in data)
{<tr>
<td>#row.columnname</td>
</tr>
}
Didn't work either. -> NullOperation Exception
I Googled all week and conducted loads of failed experiments. At my wit's end now; expert help will be greatly appreciated. Thank you...
In the first section of your code, you declare a variable for your data, but you don't query the database at all. I'm not completely clear what you are trying to do but if you want to populate the grid with data, you should query the database:
var db = Database.Open("database");
var jobquery = "select description from match_jobs";
var data = db.Query(jobquery);
var grid = new WebGrid(data, canPage: false);
Then in your "html", you don't need to query the database again - you can re-use the variable that already holds the data:
<div id="dynamic">
Select Job
<form name = "search" method="post">
<select name="job">
<option value="" selected disabled>Select Job</option>
#foreach (var row in data)
{
<option value="#Request["job"]">#row.description</option>
}
</select>
<input type="submit" value="#Request["job"]"/>
</form>
</div>
The section of code in the IsPost condition makes no sense at all. You query the database and then call Response.Redirect - telling the browser to request a different page. All values in the current page - including the data you have just retrieved are discarded when you do this.
I am not sure if this is possible, and have not found any similar questions on this.
We have an Edit View that is NOT for a single record, but for the multiple members of a "parent" record. These "child" record need to be edited together (at the same time). ... if possible.
One field in each of these "child" records is a reference to another table, so a select list is required. We use DropDownListFor in all of our standard Edit Views, and the single record edits fine.
Our model for this issue is :
[Display(Name = "Team Member")]
public int Contact_ID { get; set; }
[Display(Name = "Team Member")]
public String Contact_Name { get; set; }
[Display(Name = "Type/Role")]
public int MemberTypeLookUp_ID { get; set; }
[Display(Name = "Type/Role")]
public String MemberTypeValue { get; set; }
[Display(Name = "Type/Role")]
public LookUpList MemberTypeLookUp { get; set; }
We retrieve the first 4 fields via a select from a database table. Straightforward and OK..
Our code to set up the DropDownListFor is :
(edit : new code added within the foreach() loop to manually set the .Selected property of the relevant option within each list to true. This still does not translate over to the actual displayed View...)
foreach (TeamEditViewItem tevi in this.members)
{
tevi.MemberTypeLookUp = new LookUpList("TeamMemberType");
foreach (SelectListItem item in tevi.MemberTypeLookUp.list)
{
if (item.Value == tevi.MemberTypeLookUp_ID.ToString())
{
item.Selected = true;
break;
}
}
}
For completion of this question, the LookUpList code is :
public class LookUpList
{
public SelectList list;
// Return all Active LookUp entries for the passed-in Category.
public LookUpList(String Category)
{
WorkpointContext _db = new WorkpointContext();
int Customer_ID = _db.GetCustomer_ID();
IList<LookUp> items = (from lookup in _db.LookUp
where (lookup.Category == Category)
&& (lookup.IsActive == true)
orderby lookup.DisplayOrder ascending
select lookup).ToList();
this.list = new SelectList(items, "ID", "Value");
}
}
As mentioned, the LookUpList code is fine for a single record on a standard Edit View.
After rendering the page, we get the multiple "child" records listed, however the DropDown List does not hold the existing value for each record. (This is an EDIT not a Create, so values have already been assigned via defaults and other logics - not via DropDown lists on the Create View.
When viewing the source of the page, I can see that each of the DropDown Lists have their own ID.
I have a feeling that our issue is due to the multiple DropDownListFor objects on the page, but cannot figure out WHAT the issue is and WHY we have the issue.
Our View has simple code for the DropDownList :
#Html.DropDownListFor(model => model.members[i].MemberTypeLookUp_ID, Model.members[i].MemberTypeLookUp.list, "--Select--")
#Html.ValidationMessageFor(model => model.members[i].MemberTypeLookUp_ID)
The third parameter has been added because we were always getting the first option in the DropDown Lists and needed to determine if there was a value or not.
We are constantly getting the "--Select--" option displayed in the DropDown Lists, which is a placeholder and not a valid option - therefore the Validation Message is displayed.
(Edit) I have added the complete Edit View cshtml code :
#model WebWorkPoint.Models.TeamEditView
<h3>Edit Team</h3>
#using (Html.BeginForm()) {
<fieldset>
#if (Model.members.Count>0)
{
<table>
<!-- table headings -->
<thead>
<tr>
<td style="text-align:center; border-bottom: 1px solid black; " >
<div class='editor-label'>
#Html.LabelFor(m => m.members.First().Contact_Name)
</div>
</td>
<td class="spacer-border"> </td>
<td style="text-align:center; border-bottom: 1px solid black; " >
<div class='editor-label'>
#Html.LabelFor(m => m.members.First().MemberTypeValue)
</div>
</td>
</tr>
</thead>
<!-- table rows -->
<tbody>
#for (int i = 0; i < Model.members.Count; i++)
{
<tr>
<td style="text-align:center; " >
#Html.HiddenFor(m => m.members[i].Contact_ID)
<div class="editor-field">
#Html.EditorFor(m => m.members[i].Contact_Name)
#Html.ValidationMessageFor(model => model.members[i].Contact_Name)
</div>
</td>
<td class="spacer"></td>
<td style="text-align:center; " >
<div class="editor-field">
#Html.DropDownListFor(model => model.members[i].MemberTypeLookUp_ID, Model.members[i].MemberTypeLookUp.list, "--Select--")
#Html.ValidationMessageFor(model => model.members[i].MemberTypeLookUp_ID)
</div>
</td>
</tr>
}
</table>
}
else
{
<p>There are currently no team members defined.</p>
}
<p>
<input type="submit" value="Update Team" />
#{
sAction = "/" + Model.TableNameValue + "/" + Model.TableNameValue + "Show/" + Model.TableRecord_ID.ToString();
sLinkText = "Cancel";
}
<button type="button" onclick="location.href='#sAction'" >#sLinkText</button>
</p>
</fieldset>
}
(end Edit)
Can anyone shed some light into our issue ? Thank you in advance for any help.
After reading this answer on Stack Overflow , we decided to try the same kind of resolution.
As it turns out, the FULL resolution went as follows :
We still needed to set up the LookUpList in the setup code (but did not need to attempt any select code) :
// other code above ...
foreach (TeamEditViewItem tevi in this.members)
{
tevi.MemberTypeLookUp = new LookUpList("TeamMemberType");
}
The LookUpList() code creates the SelectList as per the original issue/question - no changes required there.
We also needed to replace the DropDownListFor() call on the Edit View :
#Html.DropDownListFor(model => model.members[i].MemberTypeLookUp_ID, new SelectList(Model.members[i].MemberTypeLookUp.list, "Value", "Text", Model.members[i].MemberTypeLookUp_ID), "--Select--")
It seemed repetitive or redundant, but this is what was required. There may be something we could do to clean it further, but it "ain't broke" now, so why try to fix it ?
I must say thank you to #Stephen Muecke and #Mario Lopez for their input, to get us investigating and thinking further afield from what we were doing. Also, thank you to #ataravati for resolving the other issue linked above, to get us to try something else.
Hopefully our issue and resolution might help other coders out there ...
I think what is happening is that all the dropwdowns are being generated with the same Id = MemberTypeLookUp_ID. What I would do is creating a partial view for the child and call it from the main view inside a foreach and pass to this partial view only the child model that has to be populated for and not the whole parent model.
My site has a column that displays the news. The DIV-s with these news which contain the word "prize" must be painted in the green color. (If a person has created a record (a news) without specifying the Prize (without word "Prize"), the green is not necessary. But if a person filled out the field model.Prize (so in the text we have a word "Prize") the div must be painted in green color.
In a view for creating news there is a field model.Prize
<div class="editor-field">
#Html.TextAreaFor(model => model.Prize,4,55,null)
#Html.ValidationMessageFor(model => model.Prize)
</div>
The value of model.Prize takes the Controller which create a new news record.
public ActionResult Create(Project project)
{
if (ModelState.IsValid)
{(some code...)
News n = new News();
n.Date = DateTime.UtcNow;
n.Description = project.Shortdescription+"\r\n\Prize:\r\n"+project.Prize;
(some code…)
NewsController.Add(db,n);
db.SaveChanges();
return RedirectToAction("Main");
}
In the another method Block of News Controller I display the news:
public PartialViewResult Block()
{
List<News> news = new List<News>();
Int32 count = 0;
foreach (News n in db.News.ToList().OrderByDescending(n => n.Date))
{
if (count++ < 13) news.Add(n);
}
return PartialView(news);
For each entry in the View Block creates <div class ="newsWrapper"> in which the news record insert.
#foreach (var item in Model){
<div class ="newsWrapper">
<p class="newsDate">#item.Date.AddHours(4).ToString("dd.MM.yyyy HH:mm")</p>
#item.Title
<p>#Html.Raw(Html.Encode(item.Description).Replace("\n", "<br />"))</p>
</div>
}
I tried to solve the problem
I added the new div in the Block View:
#foreach (var item in Model)
{
<div class ="newsWrapper">
<div class="#(ViewBag.IsPrize == true ? "GreenNewsClass" : "")">
<p class="newsDate">#item.Date.AddHours(4).ToString("dd.MM.yyyy HH:mm")</p>
#item.Title
<p>#Html.Raw(Html.Encode(item.Description).Replace("\n", "<br />"))</p>
</div>
</div>
}
The GreenNewsClass will paint this div in green color.
But how can I get ViewBag.IsPrize == true if n.Description contains the word Prize,
and ViewBag.IsPrize == false if it's not?
I tried to change the method Block:
public PartialViewResult Block()
{
List<News> news = new List<News>();
Int32 count = 0;
foreach (News n in db.News.ToList().OrderByDescending(n => n.Date))
{
if (count++ < 13) news.Add(n);
if (n.Description.Contains("Призы"))
{
ViewBag.IsPrize = true;
}
else { ViewBag.IsPrize = false; }
}
return PartialView(news);
but it paints all news in green color, not only those which contain the word Prize.
It sounds like you want to do this:
#foreach (var item in Model)
{
<div class ="newsWrapper">
<div class="#(item.Description.Contains("Призы") ? "GreenNewsClass" : "")">
<p class="newsDate">#item.Date.AddHours(4).ToString("dd.MM.yyyy HH:mm")</p>
#item.Title
<p>#Html.Raw(Html.Encode(item.Description).Replace("\n", "<br />"))</p>
</div>
</div>
}
First try to add a property to your model instead to your ViewBag, it seems like you only have a single value in your ViewBag.
Remove the true condition because it's redundant, move the class definition inside the condition that way the div will be empty when the condition is false
and try the following:
#foreach (var item in Model)
{
<div class ="newsWrapper">
<div #(item.IsPrize? "class=GreenNewsClass" : "")>
<p class="newsDate">#item.Date.AddHours(4).ToString("dd.MM.yyyy HH:mm")</p>
#item.Title
<p>#Html.Raw(Html.Encode(item.Description).Replace("\n", "<br />"))</p>
</div>
</div>
}
I have not verified the code but try it out.