i want to bring the partial view of question link list to my edit view. However, when i select the groupby value, it shows the error below. Please guide me.
The model item passed into the dictionary is of type
'System.Collections.Generic.List1[<>f__AnonymousType42[SurveyTool.Models.SURV_Question_Ext_Model,SurveyTool.Models.SURV_Question_Model]]',
but this dictionary requires a model item of type
'System.Collections.Generic.IEnumerable`1[SurveyTool.Models.SURV_Question_Ext_Model]'.
Edit view:
#model IFXSurveyTool.Models.SURV_Main_Model
<div class="question">
<h2>Link</h2>
#Html.Action("QuestionLink", "SURV_Main", new { Survey_ID = Model.Survey_ID })
</div>
Controller:
public ActionResult QuestionLink(int Survey_ID)
{
var query = from r in db.SURV_Question_Ext_Model
join s in db.SURV_Question_Model on r.Qext_Question_ID equals s.Question_ID
where s.Question_Survey_ID == Survey_ID
group new { r, s } by r.Qext_Language into grp
select grp.FirstOrDefault();
return PartialView(query.ToList());
}
QuestionLink view:
#model IEnumerable<SurveyTool.Models.SURV_Question_Ext_Model>
<br />
<table class="strip">
#foreach (var item in Model)
{
<tr>
<td width="5%"></td>
<td>
#Html.ActionLink("QuestionLink", "Edit", "SURV_Answer", new { Language = item.Qext_Language }, null)
</td>
</tr>
}
</table>
Please change following line in Your PartialView code:
#model IEnumerable<SurveyTool.Models.SURV_Question_Ext_Model>
to:
#model List<SurveyTool.Models.SURV_Question_Ext_Model>
Or returning type in controller. Types needs match.
From comments:
there is also returned group of LINQ query, so it's anoumous Type, not the one You expecting.
You have little error. Try this:
#model IEnumerable<SurveyTool.Models.SURV_Question_Ext_Model>
<br />
<table class="strip">
#foreach (var item in Model)
{
<tr>
<td width="5%"></td>
<td>
#Html.ActionLink("Edit", "QuestionLink", "SURV_Answer", new { Language = item.Qext_Language }, null)
</td>
</tr>
}
Related
I'm joining multiple tables using linq. The problem is, I have to join a table, that will have some null values in some rows. I think the join itself is working fine, but when I iterate through my ViewBag, I get an error because of the null values.
This is my code:
Controller:
ViewBag.coaching = (from kst in db.kursister
join kursus_kursist in db.kursus_kursist
on kst.kursist_id equals kursus_kursist.kursist_id
join kursus in db.kurser
on kursus_kursist.kursus_id equals kursus.kursus_id
join coach in db.jobcoach
on kst.kursist_id equals coach.kursist_id into coachJoin
where kursus.kursus_id == id
from cj in coachJoin.DefaultIfEmpty()
select new CoachHoldModel { kst = kst, kursus = kursus, cj = cj });
Here's my view:
#model IEnumerable<Itucation.Models.CoachHoldModel>
#{
ViewBag.Title = "Karriere Coach Hold";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Protokol</h2>
<div>
<h3>
#{
foreach (var navn in (ViewBag.kursus))
{
#navn.kursus_navn
}
}
</h3>
<table class="table-bordered">
<tr>
<td colspan="2" style="border:0;"></td>
<th>Status</th>
<td><img src="~/Content/Images/logo.png" height="30" /></td>
</tr>
#{
foreach (var item in (ViewBag.coaching))
{
<tr>
<td>#item.kst.fornavn</td>
<td>#item.kst.efternavn</td>
<td>
#item.cj.status
</td>
<td colspan="2"></td>
</tr>
}
}
</table>
</div>
It is the #item.cj.status that will contain null values.
The forech loop iterates through a list of students. Some students have a status set, some do not. i would like to display the value for the students, who have a status value - and ignore the others.
Any help would be greatly appreciated.
Why not test if it's not null and then show the status?
<td>
#if (item.cj != null) // or item.cj?.status
{
<span>#item.cj.status</span>
}
</td>
I tried a code like this, it works quite well:
View:
#model IEnumerable<InternProject.Models.Course>
....
#Html.ActionLink("Create New", "Create")
#using (Html.BeginForm("Index", "Course", FormMethod.Get))
{
<p>
#Html.TextBox("searching")
<input type="submit" value="search" />
</p>
}
<table class="table table-striped">
<thead>
<tr>
<th>Course ID</th>
<th>Course Name</th>
<th>Major</th>
<th>Specialization</th>
<th></th>
</tr>
</thead>
#foreach (var item in Model) {
<tr>
<td>#Html.DisplayFor(modelItem => item.crs_ID)</td>
<td>#Html.DisplayFor(modelItem => item.crs_Course)</td>
<td>#Html.DisplayFor(modelItem => item.crs_Major)</td>
<td>#Html.DisplayFor(modelItem => item.crs_Specialization)</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.crs_ID }) |
#Html.ActionLink("Details", "Details", new {id = item.crs_ID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.crs_ID })
</td>
</tr>
}
</table>
Controller:
public class CourseController : Controller
{
private DbCourse db = new DbCourse();
public ActionResult Index(string submit, string searching)
{
var course = from x in db.Course select x;
if (!String.IsNullOrWhiteSpace(searching))
{
return View(db.Course.Where(x => x.crs_Course.Contains(searching.Trim()) ||
x.crs_Major.Contains(searching.Trim()) ||
x.crs_Specialization.Contains(searching.Trim())).ToList());
}
else if (searching == null)
{
return View(db.Course.Where(x => x.crs_Course == searching || searching.Trim() == null).ToList());
}
else
{
return View(db.Course.ToList());
}
}
}
But the id cannot be included because it is an integer. I want to have a solution wherein I can search also in the id of my database depending on the input in the search box.
Also, is there a better code than this for a simple search functionality like this? I've noticed it's so long and it obviously violates the DRY principle.
Here is what my simple application looks like:
I'm taking my baby steps in ASP.NET MVC as a beginner.
I hope to improve my knowledge using applied coding and not just relying on tutorial videos.
Thank you very much in advance! =)
The simplest solution would be to convert the ID to a string. Your code then become the following.
return View(db.Course.Where(x => x.crs_Course.Contains(searching.Trim()) ||
x.crs_Major.Contains(searching.Trim()) ||
x.crs_Specialization.Contains(searching.Trim()) ||
x.crs_crs_ID.ToString().Contains(searching.Trim())).ToList())
This doesn't go against the DRY principle since you're using Contains() on different variables; however, what is going against the DRY principle is the repetitive searching.Trim(). I suggest you trim the string once at the top of your code.
var match = searching.Trim();
Then you can use match instead of searching.Trim() in the code below.
I'm trying to make a table using partial view from another view.
the content of the view I want to desplay:
#model Agro1.ModelView.MessageViewModel
#using Agro1.Models
<span style="color:darkgreen">Messages</span>
<br />
<table>
<tr>
<td>Subject</td>
<td>Content</td>
<td>Farmer Email</td>
</tr>
#{
foreach (Message obj in Model.messages)
{
<tr>
<td>#obj.Subject</td>
<td>#obj.Content</td>
<td>#obj.FarmerEmail</td>
</tr>
}
}
</table>
in another view I want to desplay only the 5 first rows of this table.
now my code in the view looks like this:
#Html.Partial("DisplyaMessages",Model)
and it shows the full table.
how can I desplay only the 5 first rows?
t
You could use linq syntax .take(5) either in the controller action or in the razor.
Your razor code would look like this:
#{
foreach (Message obj in Model.messages.take(5))
{
<tr>
<td>#obj.Subject</td>
<td>#obj.Content</td>
<td>#obj.FarmerEmail</td>
</tr>
}
You should add a new property into the model with the max rows to display.
After that you can check this property during the foreach.
#model Agro1.ModelView.MessageViewModel
#using Agro1.Models
<span style="color:darkgreen">Messages</span>
<br />
<table>
<tr>
<td>Subject</td>
<td>Content</td>
<td>Farmer Email</td>
</tr>
#{
var x = 0;
foreach (Message obj in Model.messages)
{
if (Model.MaxRows > 0 && x > Model.MaxRows) break;
<tr>
<td>#obj.Subject</td>
<td>#obj.Content</td>
<td>#obj.FarmerEmail</td>
</tr>
x++;
}
}
</table>
You can call the partial creating a new model like this:
#Html.Partial("DisplyaMessages", new MessageViewModel { MaxRows = 5, messages = Model.messages})
after generating a question list to let user key in, i will like to post their input and save into database, but my view model can't get what user key in in the textfield. Any hint or guidance?
My viewmodel:
#model List<SurveyTool.Models.AnswerQuestionViewModel>
#{
ViewBag.Title = "Edit";
}
<br/>
<h2>Questions</h2>
<br/>
#using (Html.BeginForm())
{
<table>
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.HiddenFor(m => m[i].Survey_ID)
#Html.HiddenFor(m => m[i].MaxChar)
#Html.DisplayFor(m => m[i].Question)
</td>
</tr>
<tr>
#switch (Model[i].Type)
{
case "Info_Text":
{
<td></td>
}
break;
case "Single_Line":
{
<td>
#Html.EditorFor(m=>m[i].Answer, new { #maxlength = Model[i].MaxChar}) << textbox to input answer.
</td>
}
break;
case "Multiple_Line":
{
<td>
#Html.TextAreaFor(m => m[i].Answer)
</td>
}
break;
}
</tr>
}
</table>
<input value="Submit" type="submit" class="btn" />
}
My Controller:
[HttpPost]
public ActionResult SURV_Answer_Submit(AnswerQuestionViewModel viewmodel)
{
if (ModelState.IsValid)
{
var query = from r in db.SURV_Question_Ext_Model.ToList()
join s in db.SURV_Question_Model
on r.Qext_Question_ID equals
s.Question_ID
where s.Question_Survey_ID == viewmodel.Survey_ID && r.Qext_Language == viewmodel.Language
orderby s.Question_Position ascending
select new { r, s };
foreach(var item in query)
{
var answer = new SURV_Answer_Model();
answer.Answer_Qext_ID = item.r.Qext_Question_ID;
answer.Answer_Data = viewmodel.Answer; << can't get input!
db.SURV_Answer_Model.Add(answer);
db.SaveChanges();
}
return RedirectToAction("SURV_Main_Index", "SURV_Main");
}
return View(viewmodel);
}
You model in the view is defined as #model List<AnswerQuestionViewModel> which means the POST method signature need to be changed to
public ActionResult SURV_Answer_Submit(List<AnswerQuestionViewModel> viewmodel)
The use a loop to access each item in the model and save.
However there are also some other issues. The DefaultModelBinder required collection indexers to start at zero and be consecutive, but your #switch (Model[i].Type) statement means that a form control for Answer may not be rendered. To ensure binding does not fail when you submit, include a hidden input for case "Info_Text":.
You also do not include a form control for the Type property so if ModelState is invalid and you return the view, your code would fail (the value of Type will be null) so you either need to include a hidden input or call the database again to get the values before returning the view.
I have this view based on a list of a model where I create strongly-typed checkboxes for each items of the model based on a boolean.
Here's my view:
#using MyApp.Models
#model IList<MyApp.Models.ObjInfo>
#{
ViewBag.Title = "Obj Inventory";
}
<h2>Search Inventory</h2>
<p>
#using (Html.BeginForm())
{
(Many search filters which are non-relevant)
<p>
Send Items: #Html.ActionLink("Click Here", "SendItems")
</p>
}
<table>
<tr>
<th>
Obj Name
</th>
<th>
Number In Stock
</th>
(...)
<th>
Select Item
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.OtherObj.m_Name)
</td>
(...)
<td>
#Html.CheckBoxFor(modelItem => item.m_IsSelected)
</td>
</tr>
}
</table>
The whole process works fine and I can actually generate a view with checkboxes for each item of my list of model.
Now my question is that I want to create a list which would regroup only the items in the list which are checked and send them to the controller. How could I do that? Can anyone help me or suggest me a way to work?
Thank you!
* EDIT *
Here is the HttpPost Method used to get the List of items as mentioned below:
//
// GET: /Inventory/SendItems
[HttpPost]
public ActionResult SendItems(IList<ObjInfo> listToSend)
{
m_ListObjToSend = new List<ObjInfo>();
foreach (var item in listToSend.Where(item => item.m_IsSelected))
{
m_ListObjToSend .Add(item);
}
return View(m_ListObjToSend );
}
However I have encountered many problems:
This method does NOT work if I put the [HttpPost] attribute (it will show as "Not Found");
The list I am supposed to receive is null;
Each hiddenfield linked with the checkbox has default value as false even if the checked value shows true;
I am using an actionlink because I do not want to use a button, there is already one that is doing another job.
I am open for any comments / help available, thank you!
If you use the CheckBoxFor helper to generate checkboxes you will notice that it generates an additional hidden field along with each checkbox. This means that all values will be sent to the controller and you will have to filter in your controller those that are checked.
Also I would recommend you using indexes to ensure proper model binding. You just need to use an IList<ObjInfo> or ObjInfo[] which is trivially easy achievable by calling .ToList() or .ToArray() extension methods on your view model before passing it to the view:
#using MyApp.Models
#model IList<ObjInfo>
...
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(x => x[i].OtherObj.m_Name)
</td>
(...)
<td>
#Html.CheckBoxFor(x => x[i].m_IsSelected)
</td>
</tr>
}
...
And now your controller action could directly take the list of items:
[HttpPost]
public ActionResult SomeAction(IEnumerable<ObjInfo> model)
{
...
}
and if you wanted to find the selected values, you could simply get them through LINQ:
[HttpPost]
public ActionResult SomeAction(IEnumerable<ObjInfo> model)
{
var selectedItems = model.Where(x => x.m_IsSelected);
...
}
Remark: m_Name and m_IsSelected is a disastrously bad naming convention for a properties in C#.
UPDATE:
Another issue you have with your code is that your Html.BeginForm doesn't contain any input field. It has only a single ActionLink which obviously only does a GET request. If you want to submit the values you should wrap your entire table with the form and use a submit button and not some action links:
#using MyApp.Models
#model IList<ObjInfo>
#{
ViewBag.Title = "Obj Inventory";
}
<h2>Search Inventory</h2>
<p>
#using (Html.BeginForm("SendItems", null, FormMethod.Post))
{
(Many search filters which are non-relevant)
<table>
<tr>
<th>Obj Name</th>
<th>Number In Stock</th>
(...)
<th>Select Item</th>
</tr>
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
<!--
This will not be sent to your controller because it's only a label.
You will need a corresponding hidden field if you want to get that value back
-->
#Html.DisplayFor(x => x[i].OtherObj.m_Name)
</td>
(...)
<td>
#Html.CheckBoxFor(x => x[i].m_IsSelected)
</td>
</tr>
}
</table>
<p>
Send Items: <button type="submit">Click Here</button>
</p>
}
</p>
So really, 2 things you should learn:
The naming convention that the default model binder expects when binding to a list
How to use a javascript debugging tool (such as FireBug and/or Chrome Developper Toolbar) which will allow you to inspect all the values that are sent to your server and immediately recognized whether you respected the convention you learned in 1.