I'm working on my first MVC project and I wanted to see if there's a better way to do this. I'm pretty sure there is.
I'm building an application for audits. Each audit has a list of questions, and each question has a list of options to select from. The questions and options can change. So, I have to dynamically build the table of questions and the dropdowns with the question's options.
Here's how I'm creating the SelectLists in the controller
foreach (var r in employeeAuditData.Audit.AuditResults)
{
ViewData["Result" + r.AuditQuestionID] =
new SelectList(r.AuditQuestion.QuestionOptions, "QuestionOptionID", "OptionText", r.QuestionOption);
}
And here's the code for my view
foreach (var r in Model.Audit.AuditResults.OrderBy(r => r.AuditQuestion.Ordinal).ToList())
{
<tr>
<td>#r.AuditQuestion.QuestionText</td>
<td>#Html.DropDownList("Result" + r.AuditQuestionID, "(Select)")</td>
</tr>
}
This works but using concatenation for the ViewData key seems like a funky way to do this. Is there a better way?
How about making a ViewModel?
class AuditResultSelectList
{
int QuestionId { get; set;}
SelectList QuestionOptions { get; set;}
}
Then in your controller:
List<AuditResultSelectList> list = new List<AuditResultSelectList>();
foreach (var r in employeeAuditData.Audit.AuditResults)
{
AuditResultSelectList a = new AuditResultSelectList()
{
QuestionId = r.AuditQuestionID,
QuestionOptions = new SelectList(r.AuditQuestion.QuestionOptions, "QuestionOptionID", "OptionText", r.QuestionOption)
}
list.Add(a);
}
ViewData["QuestionSelectLists"] = list;
Then your view can pull the list out using:
var x = (List<AuditResultSelectList>) ViewData["QuestionSelectLists"];
Related
I have the following models:
class Order
{
public List<Product> Products { get; set; }
}
class Products
{
public int Price { get; set; }
}
In my razor page I want to loop over all products and to be able to add them to my order, like this:
int i = 0;
foreach (Product p in AllProducts)
{
<input asp-for="order.Products[i].Price">
i++;
}
This works fine when creating a new order (when the list pf products is empty), but when I try to edit the order, and maybe add new products or edit the existing ones, I'm getting an Index was out of range. exception.
Obviously because there are more products in AllProducts than there are in the order's Products list.
Is there a way to overcome this?
We can do by update code. I think resolved issue. Problem was in foreach loop.
int i = 0;
foreach (Product p in AllProducts)
{
<input asp-for="AllProducts[i].Price">
i++;
}
Still, you are facing the issue please share razor view.
How about just looping after the last index of your current orders:
int i = order.Products.Count();
foreach (Product p in AllProducts)
{
<input asp-for="order.Products[i].Price">
i++;
}
While getting the order from the DB for editing, you need to fetch the associated products as well. You can use Include to fetch them. See here for more details on that. Once you get the products, then you can use the products to list and also use the AllProducts to enable the use to add the products which were not in the list
Try the following modification in Edit order page:
#for (int i = 0; i < Model.Order.Products.Count(); i++)
{
<input asp-for="Order.Products[i].Price">
}
I have this list so far:
List<object> lista = new List<object>();
foreach (var item in group)
{
lista.Add(new
{
ver = item.FirstOrDefault().vereda.DESCRIPCION,
prod = item.Count()
});
}
ViewBag.veredasEncu = lista;
i have to send that data to a view in order to build a table:
<tbody>
#{
if (ViewBag.veredasEncu != null)
{
List<object> lis = ViewBag.veredasEncu;
for (int i = 0; i < lis.Count(); i++)
{
<tr>
<td></td>
<td></td>
</tr>
}
}
}
</tbody>
I cant get to place the info on the <td> tags cose every item in the foreach iteration throws something this:
item = {ver = "Loma", prod = 5}
how can i make that 2 values look like an array, or is there a way to separate them in order to place them in the correct tag?
I solved the issue by creating a class:
public class dataTab
{
public string ver { get; set; }
public int prod { get; set; }
}
then is just change the loop for this:
lista2.Add(new dataTab
{
ver = item.FirstOrDefault().vereda.DESCRIPCION,
prod = item.Count()
});
so it could be post in the HTML like this:
foreach (var item in ViewBag.veredasEncu)
{
<tr>
<td>#item.ver</td>
<td>#item.prod</td>
</tr>
}
However im not sure that creating a class for every type of list that i need to create is a good idea. IF someone have an idea on how to fill the list in a more generic way please respond this.
I'm currently in the process of trying to figure out a way to match data in a view model to data in a query and pass it conditionally to the view.
I have achieved this so far, however when I try to set a ViewModel value equal to a list in my query, I can't seem to find the right syntax to make it happy.
So far I have this:
public IEnumerable<QuestionViewModel> QuestionRead(int i)
{
IEnumerable<Question> questions = _repository.GetQuestions(i);
foreach (Question q in questions)
{
switch (q.Type)
{
case QuestionType.TextBasic:
return questions.ToList().Select(question =>
new QuestionViewModel
{
QuestionText = question.QuestionText,
QuestionId = question.QuestionId,
OrderIndex = question.OrderIndex + 1,
// ActualAnswer = question.Answer.TextAnswer.
});
case QuestionType.Multi:
return questions.ToList().Select(question =>
new QuestionViewModel
{
QuestionText = question.QuestionText,
QuestionId = question.QuestionId,
OrderIndex = question.OrderIndex + 1,
// ActualAnswer = question.Answer.AnswerOptions.OptionText
});
}
}
return null;
}
When I get to the point of returning the ViewModel object called actual answer, which is a list, I'm trying to reach into the query and grab the list inside of the query. The query returns the data from 3 tables, and question.Answer.TextAnswer is a string, but I want to add it to a list. The reason for this is that I have another object called MultiAnswer that is a list.
Since all answers have to fit into one grid column, I want to set to the type to list so it can accomodate 1 or more items when displaying them. I thought about doing a linq query ActualAnswer = question.Answer.TextAnswer.ToList(), but this doesn't seem to work.
I have tried various ways to get this to work. I think maybe I have something missing in my model or controller, so I'm posting all three parts.
I have data in a database that shows some advising topics chosen by an advisor in a previous appointment. When the advisor calls up that appointment, the app should display a list of all possible topics with the ones previously chosen highlighted. Everything works except that last bit.
I know I'm retrieving the right information because I can display the selected items separately. I just can't get them to show up selected. Here's the code. I'm cutting out irrelevant parts.
public class AppointmentModel
{ ...
public string AdvisingTopicId { get; set; }
public List<SelectListItem> AdvisingIdList { get; set; }
public SelectList AdvisingTopicNames { get; set; }
}
public class HomeController : AdvisorBaseController
{ ...
var topicCodes = appointment.advising_topic.ToList();
var advisingTopics = new SelectList((from t in topicCodes
select t.name).ToList(), "name");
var topicsList = (from t in db.advising_topic
select new SelectListItem
{
Selected = false,
Text = t.name,
Value = SqlFunctions.StringConvert((double)t.advising_topic_id).Trim()
}).ToList();
foreach (var topicCode in topicCodes)
{
var selTopic = topicsList.Find(x => x.Value == topicCode.advising_topic_id.ToString());
if (selTopic != null)
{
selTopic.Selected = true;
}
} ...
var appointmentModel = new AppointmentModel
{ ...
AdvisingTopicNames = advisingTopics,
AdvisingIdList = topicsList,
};
and then the view
#model AcademicAdvising.Models.AppointmentModel
<h3>Advising Topics</h3>
<ul>
#foreach (var item in Model.AdvisingTopicNames)
{
<li>#Html.DisplayFor(x => item)</li>
}
</ul>
#Html.ListBoxFor(m=>m.AdvisingIdList, new SelectList(Model.AdvisingTopicNames, "Value", "Text", Model.AdvisingTopicNames.SelectedValue))
Note that the foreach correctly displays the selected items. That's just for testing and will be pulled out. the ListBoxFor is where I'm struggling. What I have here doesn't work (shows the full list with nothing highlighted). And that's the bit where I have tried various approaches, with all fails.
It looks like you may have accidentely went a level too deep. You already have a select list which is all the listboxfor function wants.
#Html.ListBoxFor(m=>m.AdvisingIdList, Model.AdvisingTopicNames)
But honestly looking at how you are defining your lists I think what you really want might be
#Html.ListBoxFor(m=>m.AdvisingIdList, Model.AdvisingIdList)
I am creating a Pie Chart and its name-value pair are being retrieved from the database.
how to read the row details in order to get the values and store it one property ?
public override void OnApplyTemplate()
{
Ram.DataContext = new List<UsageRAM>()
{ new UsageRAM() { name = "Available" , value =/*how to get the value here*/ },
new UsageRAM() { name = "Used" , value =/*how to get the value here*/ }};
base.OnApplyTemplate();
}
public class UsageRAM
{
public string name { get; set; }
public double value { get; set; }
}
EDIT
--Answer which worked for me--
using (DB db = new DB())
{
var row = (from c in db.UsageRAMs
orderby c.UsageRamID descending
select c).First();
Ram.DataContext = new List<UsageRAM>()
{ new UsageRAM() { name = "Available" , value = row.Available},
new UsageRAM() { name = "Used" , value = row.Used }};
If you're using EF, simply add a new model to your project and include the requried table(s) in this model. Then you can use the newly created Entities object to read your db values as follows:
var Rows = context.YourTableName.Where(YourCondition).ToArray();
You can then iterate over the Rows collection using foreach or something.
If you need to read values from a single row, you may want to use First instead of Where above. That will return a single object whose properties will map to your db fields and can directly be assigned in the example code you posted in the question.
EXAMPLE
Say your model's Entity class is named MyEntities and it contains the table UsageRam, which has two fields Available and Used. Then it will take the following code:
using(MyEntities e = new MyEntities)
{
var Row = e.MyTable.First(x => x.UsageRamID = **[ID]**);
MessageBox.Show("Available=" + Row.Available.ToString() + ",Used=" + Row.Used.ToString();
}
I have just shown values in message box, you can assign them to anything you want.
Another Example
using(MyEntities e = new MyEntities)
{
var Rows = e.MyTable.Where(x => x.UsageRamID > 10 && x.UsageRamID < 20);
foreach(var Row in Rows)
MessageBox.Show("Available=" + Row.Available.ToString() + ",Used=" + Row.Used.ToString();
}
EXAMPLE 3
The code in your updated post appears fine to me, though I do have some doubts about the db design, but given your table is indexed on RamUsageID column, this should give you correct results without much performance impact. I generally prefer lambada expressions over query, so I'd rather write it like:
db.RamUsage.OrderByDescending(x => x.RamUsageID).First()