passing collection to view - c#

I have multiple methods that return either a simple type (string, ..) & methods that return collections Collection<Tuple<Model_name, string>>
I tried with a simple Collection<string> at first but when i used a Tempdata to pass the collection to the view it doesn't work.
Example :
Controller:
public ActionResult Index()
{
Collection<string> test_Q_Q = new Collection<string>();
test_Q_Q.add("abcd");
test_Q_Q.add("adbc");
Tempdata["test"] = test_Q_Q;
return view();
}
View:
<!--Bla Bla here-->
#foreach (var lst in Tempdata["test"]) //error here
{
<li> </li>
}

The real issue is that TempData is a stupid dictionary, and doesn't know that there's an IEnumerable stored in it's data. If you really wanted to stick with this approach, simply cast the TempData to the appropriate type, like so:
#foreach (var lst in (Collection<string>) TempData["test"])
{
<li> #lst </li>
}
Having said that, I don't think you should be using TempData. What I recommend is using a strongly typed Model object that gets passed into the view, something like this in the controller:
var model = new MyCustomType();
model.ListOfStrings = new Collection<string>();
model.ListOfStrings.Add("foo");
model.ListOfStrings.Add("blah"); // You get the idea
return View(model);
Then, in your view declare the type like so at the top:
#model MyCustomType
And address it like this:
#foreach (var item in Model.ListOfStrings)
{
<li> #item </li>
}
At the very least, I hope you would use ViewBag instead of TempData. As some of the comments have mentioned, TempData has a particular use, having to do with the lifetime of the HTTP request, and is not meant to be used the way you're using it. Good Luck!

Try closing your foreach loop test.
<!--Bla Bla here-->
#foreach (var lst in Tempdata["test"] ) // Close
{
<li> ???? </li>
}

Related

How to dynamically create several ActionLinks from the Controller in MVC?

I'm using MVC where I have a list of strings that I would like to point to a new page. I'm using Razor and am very new to MVC and cannot seem to find the answer to my question through google.
My list could contain of the following:
"hello"
"goodbye"
"seeya"
I know how to insert strings from the controller to the html page using ViewBag, and I would use the following actionlink if I had a fixed set of strings:
#Html.ActionLink("viewedName", "ChemicalClass", new { mystring = "hello" })
#Html.ActionLink("viewedName", "ChemicalClass", new { mystring = "goodbye" })
#Html.ActionLink("viewedName", "ChemicalClass", new { mystring = "seeya" })
As I understand it, this would generate 3 links that would redirect to the subpage "ChemicalClass", and it would contain the one of the 3 parameters, depending on the link that was clicked.
My quesiton is, how can I do the same, but have the ActionLinks created dynamically, since I won't know how many links are going to be created, nor the content of the strings. My goal is to show these links on the webpage in (preferabely) a list form, e.g.:
<ol>
<li>
hello
</li>
<li>
goodbye
</li>
<li>
seeya
</li>
</ol>
Where each element in the list is a link and not just a string.
Create a view model that stores a collection of links
Model
public class ViewModel
{
public IList<string> Links { get; set; }
}
populate that model in your controller
Controller
public ActionResult Index()
{
var model = new ViewModel
{
Links = new List<string>
{
"Hello",
"Goodbye",
"Seeya"
}
};
return View(model);
}
and finally your view
View
#model MvcApplication1.Models.ViewModel
<ol>
#foreach (var item in Model.Links)
{
<li>
#Html.ActionLink("viewedName", "ChemicalClass", new { mystring = item })
</li>
}
</ol>
Your class holds your collection of strings and razor loops over them to produce your links.
you can use something like this.
<ul>
#foreach (var x in Model)
{
<li>#x.myString </li>
}
</ul>
I have something like this in one of my Views:
#foreach (var item in Model.MyList)
{
<li>
#Html.ActionLink("Select", "ActionName", "Chemical", new {id = item.AdmNum}, new { #class = "label label-info"})
</li>
}

Why I can't pass this object from a view to a controller method?

In a view I have something like this:
<ul data-role="listview" data-inset="true" data-theme="b" data-split-icon="delete">
#foreach (DataModel.Vulnerability.Fix item in Model.VulnerabilityFixes)
{
<li><a href="#Url.Action("Details", "Product", new { Title = item.Title })">
<h2>#item.Title</h2>
<table style="width: 100%">
<tr>
<th>Id</th>
<th>FixName</th>
<th>Vendor</th>
<th>Version</th>
</tr>
<tr>
<td>#MyHelper.decodeNull(item.Id)</td>
<td>#MyHelper.decodeNull(item.FixName)</td>
<td>#MyHelper.decodeNull(item.Vendor)</td>
<td>#MyHelper.decodeNull(item.Version)</td>
</tr>
</table>
</a>
Delete
</li>
}
</ul>
As you can see it show a table and this table have a delete button that clicked call a DeleteFix() method on an EditingController class and this method take 2 paramethers that are:
vulnId = Model.Id that is a long
the current item that is a DataModel.Vulnerability.Fix object.
So this is the code of my DeleteFix() definied into my EditingController class:
public ActionResult DeleteFix(long vulnId = 0, DataModel.Vulnerability.Fix currentFix)
{
DataModel.Vulnerability.Fix model = new DataModel.Vulnerability.Fix();
manager.openConnection();
try
{
model = currentFix;
}
finally
{
manager.closeConnection();
}
return View(model);
}
The problem is that give me the following error on the signature of this method refered to the second input parameter (the DataModel.Vulnerability.Fix object). It say to me that:
Error 14 Optional parameters must appear after all required
parameters C:\Develop\EarlyWarning\public\Implementazione\Ver2\WebPortal\WebPortal\Controllers\EditingController.cs 27 94 WebPortal
Why? What am I missing? What can I do to pass the previous DataModel.Vulnerability.Fix item object from my view to my DeleteFix() controller method?
Check your function signature:
public ActionResult DeleteFix(long vulnId = 0, DataModel.Vulnerability.Fix currentFix)
Swap the input parameters:
public ActionResult DeleteFix(DataModel.Vulnerability.Fix currentFix, long vulnId = 0)
The error is now gone. The reason is that all parameters that do not get a default value (currentFix) must appear before all parameters that do get a default value (long vulnId = 0)
update
#Neel's answer is also correct, but not related to the error you mentioned.
It's not the cause of the error, but it's also something that needs to be fixed. Assuming this isn't just a typo in the SO question :)
make changes in you actionlink as below and put currentFix instead of fix and change the sequence as below :-
(As flatter suggested )
public ActionResult DeleteFix(DataModel.Vulnerability.Fix currentFix, long vulnId = 0)
and in view
Delete
In C# you cannot declare an optional parameter BEFORE a non optional one.
Change your controller action to be:
public ActionResult DeleteFix(DataModel.Vulnerability.Fix currentFix, long vulnId = 0)

ASP.NET MVC CheckBoxList from model with List Property

Apologies if the title is unclear.
I'm trying to return my model from a form submit in ASP.NET MVC.
My question is nearly the same as this question, only differing in that I don't have a List<Model> but a model like:
public Model
{
string UserName {get; set;}
string Password {get; set;}
List<Roles> UserRoles {get; set;}
}
where I need the UserRoles as checkboxes that the admin can select from when creating a new user. My question is, I'm unsure how to use a '#Html.CheckBoxFor' against a list. I tried this:
#for (var i = 0; i < Model.UserRoles.Count();i++ )
{
#Html.HiddenFor(model => model.UserRoles[i].RoleID)
#Html.CheckBoxFor(model => model.UserRoles[i].Selected)
#Html.LabelFor(model => model.UserRoles[i].Name)
}
which in no way worked - every label on the page is "Name", and my List was empty in the POST. Can anyone offer me any guidance on this?
No need to go away from Razor at all.
This works for me:
for (var i = 0; i < Model.UserRoles.Count(); i++)
{
var role = Model.UserRoles[i];
#Html.HiddenFor(model => model.UserRoles[i].RoleId)
#Html.CheckBoxFor(model => model.UserRoles[i].Selected)
#Html.LabelFor(model=> model.UserRoles[i].Name, role.Name)
}
See below code, this way you don't need to hide the role Id, also when you save the selected roles for the user, you don't need to loop through all roles to see which role is selected.
View
#foreach (Roles info in Model.UserRoles)
{
<span>
<input type="checkbox" class="checkbox" name="selectedRoles" value="#info.RoleName" id="#infoRoleName" />
<label for="#info.RoleName">#info.RoleName</label>
</span>
}
Action
[HttpPost]
public ActionResult CreateUsers(Model model, string[] selectedRoles)
{
//
}
From your code in the view, the post should work fine providing your post action looks like this:
[HttpPost]
public ActionResult Action(Model model)
{
return View(model);
}
i.e. passing your model across as the argument.
Also make sure you have your model reference in the view too:
#model YourNameSpace.Model
Post a list of check boxes to server and get list of checked items
linq left join to check whether checked, generating checkboxes,received checked list
View
List<eDurar.Models.tbl_ISOCetificate> ModList = db.tbl_ISOCetificate.ToList();
var li = (from cert in db.tbl_ISOCetificate join comCert in db.tbl_CompCertificate on cert.Cert_id equals comCert.CompCer_id into jo from b in jo.DefaultIfEmpty()
select new {cert.Cert_id,cert.Cert_Name,chkd = b.CompCer_SerId==null?"":"checked"}).ToList();
foreach (var item in li)
{
#:<div style="width: 30%; display: inline-block; margin: 1em">
#:<input type="checkbox" #item.chkd name="CheckedCertificates" value="#item.Cert_id">
#:<label>#item.Cert_Name</label>
#:</div>
}
Controller
[HttpPost]
public ActionResult ManageSurveyGroup(int[] CheckedCertificates)
{
return View();
}

Can I use IEnumerable<> inside a View?

In _Layout.cshtml
#model DynaPortalMVC.Models.Page
#using System.Linq
<ul>
#IEnumerable<model.Page> pages = model.Where(x=>x.CompanyID == 1);
#foreach (var item in pages)
{
<li>item.Title</li>
}
</ul>
In view iam trying to filter the model object called 'page' and get a list of pages whose id is 1. I need to iterate through this to show the menu.
Code inside Controller
public ActionResult Menu(string PageName)
{
//
return View(PageName, db.Pages);
}
Please tell me, how to filter out this model object to a list? I get errors on using IEnumerable.
Solved
I changed the model object to IEnumerable in view page.
#model IEnumerable<DynaPortalMVC.Models.Page>
You can skip assigning the result of your query into an IEnumerable variable unless you will use it somewhere else on the page. So you can just do this:
#model DynaPortalMVC.Models.Page
#using System.Linq
<ul>
#foreach (var item in model.Where(x=>x.CompanyID == 1))
{
<li>#item.Title</li>
}
</ul>
You need
# {IEnumerable<model.Page> pages = Model.Where(x=>x.CompanyID == 1);}
#model IEnumerable<DynaPortalMVC.Models.Page>
#{
ViewBag.Title = "Page";
}

Model Binding with variable number of items in List<T>

I have a model that can have a variable amount of items in a List<T>
In my view I then have the following:
#using (Html.BeginForm())
{
int count = Model.Data.Filters.Count;
for(int i = 0; i < count; i++)
{
<div>
#Html.TextBox("filtervalue" + i)
#Html.DropDownList("filteroptions"+i,Model.Data.Filters[i].FilterOptions)
</div>
}
#Html.Hidden("LinkID", Url.RequestContext.RouteData.Values["id"])
}
Is there a way in my controller so I can set up the POST action method to bind to a model with variable items in it?
Also how would I construct the model to cope with this?
Thanks
You coud use editor templates, it will be much easier:
#using (Html.BeginForm())
{
#Html.EditorFor(x => x.Data.Filters)
#Html.Hidden("LinkID", Url.RequestContext.RouteData.Values["id"])
}
and inside the editor template (~/View/Shared/EditorTemplates/FilterModel.cshtml) which will be automatically rendered for each element of the Model.Data.Filters collection:
#model FilterModel
<div>
#Html.TextBoxFor(x => x.FilterValue)
#Html.DropDownListFor(x => x.SelectedFilterOption, Model.FilterOptions)
</div>
Now your POST controller action will simply look like this:
[HttpPost]
public ActionResult Foo(SomeViewModel model)
{
// model.Data.Filters will be properly bound here
...
}
Thanks to editor templates you no longer have to write any foreach loops in your views or worry about how to name your input fields, invent some indexed, ... so that the default model binder recognizes them on postback.

Categories

Resources