Passing a parameter to Html.ActionLink - c#

I am trying to pass a parameter to the Create #Html.ActionLink in the Index view however I am having some difficulties.
I have an Address controller in which the user sees the addresses of a specific person when they access the Index view. I would like to pass this PersonID to the Create view so that they do not have to select or enter the person when they create a new address. My actionlink looks like this -
#Html.ActionLink("Create New", "Create", new { id = Model.[PersonID is not a choice]})
My problem is that after Model PersonID is not an option. I am not sure how to get PersonID to the Create function in the AddressController.
I tried following along with the post - Passing a parameter to Html.ActionLink when the model is IEnumerable<T> - where they are having the same issue. The first answers seems like a likely solution however I could not duplicate the model they created and when I put the pieces in my Address model I could not duplicate the code they had performed in the controller. Is there another solution?
My Address Model -
public partial class Address
{
public int AddressID { get; set; }
public int PersonID { get; set; }
[Display(Name="Address")]
public string Address1 { get; set; }
[Display(Name = "Address 2")]
public string Address2 { get; set; }
public string City { get; set; }
[Display(Name="State")]
public string StateAbbr { get; set; }
[Display(Name = "Zip Code")]
public string Zip { get; set; }
public virtual Person Person { get; set; }
public List<Address> Address { get; set; }
}
My AddressController Index
public ActionResult Index(int id)
{
var addresses = db.Addresses.Include(a => a.Person)
.Where(a => a.PersonID == id);
Person person = db.People.Find(id);
ViewBag.FullName = person.FirstName + " " + person.LastName;
person.PersonID = id;
return View(addresses.ToList());
}
Address Index view -
#model IEnumerable<OpenBurn.Models.Address>
#{
ViewBag.Title = "Address";
}
<h2>Address</h2>
<p>
#Html.ActionLink("Create New", "Create", new { id = .PerosnID })
</p>
<h3 style="color: #008cba;"> #ViewBag.FullName </h3>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Address1)
</th>
<th>
#Html.DisplayNameFor(model => model.Address2)
</th>
<th>
#Html.DisplayNameFor(model => model.City)
</th>
<th>
#Html.DisplayNameFor(model => model.StateAbbr)
</th>
<th>
#Html.DisplayNameFor(model => model.Zip)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Address1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address2)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.StateAbbr)
</td>
<td>
#Html.DisplayFor(modelItem => item.Zip)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.AddressID }) |
#Html.ActionLink("Details", "Details", new { id=item.AddressID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.AddressID })
</td>
</tr>
}
</table>

Since the #Html.ActionLink syntax isn't inside a foreach loop, you obviously can't use IEnumerable<OpenBurn.Models.Address> as the model. You need a new model class that contains a property that holds those Address records and a property that holds the PersonID value. You should also use the same model class to pass the FullName value instead of using ViewBag. I would suggest the below model class
public class AddressIndexModel
{
public AddressIndexModel()
{
this.Addresses = new List<Address>();
}
public int PersonID { get; set; }
public string FullName { get; set; }
public List<Address> Addresses { get; set; }
}
then change your controller to this
public ActionResult Index(int id)
{
var addresses = db.Addresses.Include(a => a.Person)
.Where(a => a.PersonID == id);
Person person = db.People.Find(id);
AddressIndexModel model = new AddressIndexModel();
model.PersonID = id;
model.FullName = person.FirstName + " " + person.LastName;
model.Addresses = addresses.ToList();
return View(model);
}
and change your view to below
#model AddressIndexModel
#{
ViewBag.Title = "Address";
}
<h2>Address</h2>
<p>
#Html.ActionLink("Create New", "Create", new { id = Model.PersonID })
</p>
<h3 style="color: #008cba;"> #Model.FullName </h3>
<table class="table">
<tr>
<th>
Address
</th>
<th>
Address 2
</th>
<th>
City
</th>
<th>
State
</th>
<th>
Zip Code
</th>
<th></th>
</tr>
#foreach (var item in Model.Addresses) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Address1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address2)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.StateAbbr)
</td>
<td>
#Html.DisplayFor(modelItem => item.Zip)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.AddressID }) |
#Html.ActionLink("Details", "Details", new { id=item.AddressID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.AddressID })
</td>
</tr>
}
</table>

Related

How to show some results in Index View

I have two model classes: Artist and Album, I want to show in the Index View that belong to Artist the total amount of Albums per Artist, I want to create other column besides "Name" and "LastName" named "AlbumsTotal" with the total amount of albums produced by the artist, inside Index View, here is an example of what I want:
Name LastName TotalAlbums
Frank Sinatra 4
Celine Dion 6
I know how to do that creating a ViewModel and using other view, but I want to use the same view that belongs to Artist and display the information. Can you let me know how I can do this?
Model classes:
public class Artist
{
public int ArtistID { get; set; }
[Display(Name ="Artist name")]
public string Name { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public virtual List<Album> Albums { get; set; }
}
public class Album
{
public int AlbumID { get; set; }
public string AlbumName { get; set; }
public virtual Artist Artist { get; set; }
public int ArtistID { get; set; }
}
Index View:
#model IEnumerable<AlexMusicStore.Models.Artist>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.LastName)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ArtistID }) |
#Html.ActionLink("Details", "Details", new { id=item.ArtistID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ArtistID }) |
</td>
</tr>
}
</table>
One possible way is as follow.
Since you already have the albums in a collection on the Artist, and assuming you load all the albums of the artist into this collection, you can show the total amount of albums for the artist by using the Count() method of the List.
Change your View's code to look as follow:
#model IEnumerable<AlexMusicStore.Models.Artist>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.LastName)
</th>
<th>
#Html.DisplayName("TotalAlbums")
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#item.Albums.Count()
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ArtistID }) |
#Html.ActionLink("Details", "Details", new { id=item.ArtistID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ArtistID }) |
</td>
</tr>
}
</table>

Filtering by parameter & Routing

I have an MachineInfo view page which I am showing 60 different specifications of the related machine like processor info, ram info, disk info, db info etc.
ActionLink to this page is:
#Html.ActionLink("Machine Info", "MachineInfo", new { id = Model.LicenseKey }) |
Controller:
public ActionResult MachineInfo(string LicenseKey)
{
if (LicenseKey == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Farm farm = db.Farms.Find(LicenseKey);
if (farm == null)
{
return HttpNotFound();
}
return View(farm);
}
Farm Model:
public partial class Farm
{
public Farm()
{
this.FarmChanges = new HashSet<FarmChange>();
this.FarmDetails = new HashSet<FarmDetail>();
this.FarmTables = new HashSet<FarmTable>();
}
public int Id { get; set; }
public string LicenseKey { get; set; }
public string Name { get; set; }
public string CustomerName { get; set; }
public virtual ICollection<FarmChange> FarmChanges { get; set; }
public virtual ICollection<FarmDetail> FarmDetails { get; set; }
public virtual ICollection<FarmTable> FarmTables { get; set; }
}
FarmDetails Model:
public partial class FarmDetail
{
public System.Guid Id { get; set; }
public int FarmId { get; set; }
public int Type { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual Farm Farm { get; set; }
}
All the MachineInfo is coming from the "Value" in the FarmDetails table.
View:
#model IEnumerable<FarmManagement.Models.FarmDetail>
#{
ViewBag.Title = "Machine Info";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Machine Info</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Type)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Value)
</th>
<th>
#Html.DisplayNameFor(model => model.Farm.LicenseKey)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Type)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Value)
</td>
<td>
#Html.DisplayFor(modelItem => item.Farm.LicenseKey)
</td>
<td>
</td>
</tr>
}
</table>
#Html.ActionLink("Back to Farms List", "Index")
I am trying to show MachineInfo of a specific machine (LicenseKey=ABXYZ-XYZAB) with this url: mydomain.com/MachineInfo/ABXYZ-XYZAB
I need to filter the view by LicenseKey.
After my all tries, I'm only getting 400 - Bad Request error (Because LicenseKey == null) or getting the MachineInfo of ALL machines, not the specific machine with LicenseKey=ABXYZ-XYZAB.
What I am doing wrong?
Change your actionlink code
#Html.ActionLink("Machine Info", "MachineInfo", new { id = Model.LicenseKey })
to
#Html.ActionLink("Machine Info", "MachineInfo", new { LicenseKey = Model.LicenseKey })
As the Action link parameter name should match with the controller action parameter name.
Solved the problem after making following changes:
New Controller After Change:
public ActionResult MachineInfo(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
FarmDetail farmdetail = db.FarmDetails.Where(x => x.FarmId == id).FirstOrDefault();
if (farmdetail == null)
{
return HttpNotFound();
}
return View(farmdetail);
}
New View After Change:
#model FarmManagement.Models.FarmDetail
#{
ViewBag.Title = "Machine Info";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Machine Info</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Type)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Value)
</th>
<th>
#Html.DisplayNameFor(model => model.Farm.LicenseKey)
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Farm.FarmDetails.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(model => model.Farm.FarmDetails.ElementAt(i).Type)
</td>
<td>
#Html.DisplayFor(model => model.Farm.FarmDetails.ElementAt(i).Name)
</td>
<td>
#Html.DisplayFor(model => model.Farm.FarmDetails.ElementAt(i).Value)
</td>
<td>
#Html.DisplayFor(model => model.Farm.LicenseKey)
</td>
<td>
</tr>
}
</table>
#Html.ActionLink("Back to Farms List", "Index")
I needed to use a where sentence in Controller;
FarmDetail farmdetail = db.FarmDetails.Where(x => x.FarmId == id).FirstOrDefault();
And removed IEnumerable from the View and changed #foreach to #for with ElementAt(i).
#Html.DisplayFor(model => model.Farm.FarmDetails.ElementAt(i).Name)

The popular model item passed into the dictis of type System.Collections.Generic.List`1[X] but this dictionary requires a model item of type X

So yeah I have investigated and read a lot of responses here but they all have mismatch with data types.. I cannot figure out why this is happening.
public class RestaurantBranchModel
{
public int id { get; set; }
public string name { get; set; }
public string telephone { get; set; }
public int master_restaurant_id { get; set; }
//public RestaurantModel master_restaurant { get; set; }
public int address_id { get; set; }
//public AddressModel address { get; set; }
}
Controller
RestaurantBranchRepository RestaurantBranchRepository = new RestaurantBranchRepository();
IEnumerable<RestaurantBranchModel> Branches;
// GET: RestaurantBranch
public ActionResult Index()
{
Branches = RestaurantBranchRepository.GetBranches();
return View(Branches); //I've also tried adding .ToList()
}
View
#model IEnumerable<OrdenarBackEnd.Models.RestaurantBranchModel>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_XenonLayoutPage.cshtml";}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.name)
</th>
<th>
#Html.DisplayNameFor(model => model.telephone)
</th>
<th>
#Html.DisplayNameFor(model => model.master_restaurant_id)
</th>
<th>
#Html.DisplayNameFor(model => model.address_id)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
<td>
#Html.DisplayFor(modelItem => item.telephone)
</td>
<td>
#Html.DisplayFor(modelItem => item.master_restaurant_id)
</td>
<td>
#Html.DisplayFor(modelItem => item.address_id)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.id }) |
#Html.ActionLink("Details", "Details", new { id=item.id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.id })
</td>
</tr>
}
</table>
#section BottomScripts{}
//END OF CODE
So.. I have a the model. I pass a collection of items in the View, the View is under the LIST template for mvc, and it says i am passing a generic list but it needs a single object ? what gives??..
This is the error
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[OrdenarBackEnd.Models.RestaurantBranchModel]', but this dictionary requires a model item of type 'OrdenarBackEnd.Models.UserModel'.
Change
#Html.DisplayNameFor(model => model.name)
To
#Html.DisplayNameFor(model => model.First().name)
Basically it needs a single object and you are passing in a list.

Getting the UserName of an ApplicationUser into a view

I am trying to display the name of an author of a question but unlike the other properties of the model, the ApplicationUser.UserName property does not show in the view (it's just blank). I am using Entity Framework, MVC 5 and Razor.
My Question model:
public class Question
{
public int QuestionID { get; set; }
public string Title { get; set; }
public ApplicationUser Author { get; set; }
public string Description { get; set; }
[DisplayName("Created")]
public DateTime CreationDateTime { get; set; }
public int Rating { get; set; }
}
My QuestionController Index action:
// GET: Questions
public ActionResult Index()
{
return View(db.Questions.ToList());
}
And the view:
#model IEnumerable<Waegogi.Models.Question>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Author.UserName)
</th>
<th>
#Html.DisplayNameFor(model => model.Description)
</th>
<th>
#Html.DisplayNameFor(model => model.CreationDateTime)
</th>
<th>
#Html.DisplayNameFor(model => model.Rating)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Author.UserName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreationDateTime)
</td>
<td>
#Html.DisplayFor(modelItem => item.Rating)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.QuestionID }) |
#Html.ActionLink("Details", "Details", new { id=item.QuestionID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.QuestionID })
</td>
</tr>
}
</table>
Where am I going wrong?
You should be able to solve this by explicitly loading your relationships in your controller call:
public ActionResult Index()
{
return View(db.Questions.Include(q => q.ApplicationUser).ToList());
}

MVC return list of items to the view

Can someone please help me out. I am trying to retrieve a list of storage details from the database and simply display the list in a view.
Storage Model:
public class StorageModel
{
[Required]
[Display(Name = "Storage Name")]
public string Name { get; set; }
[Required]
[Display(Name = "Date From")]
public string DateFrom { get; set; }
[Required]
[Display(Name = "Date To")]
public string DateTo { get; set; }
[Required]
[Display(Name = "Size")]
public string Size { get; set; }
}
Controller Method:
public ActionResult ViewStorage()
{
List<CommonLayer.TblNewsStorage> storageList = new BusinessLayer.Storage().getAllStorage().ToList();
return View(storageList);
}
Data being retrieved from the BusinessLayer above:
public IQueryable<CommonLayer.TblNewsStorage> getAllStorage()
{
return this.Entities.TblNewsStorage;
}
Now I created a strongly typed view with the StorageModel using view scaffold template, however it is not working. What exactly am I doing wrong? I tried passing a var instead of a List but still it is not working. I am new to MVC so I must be doing something wrong. Which is the proper way to pass and display a list of data to a view?
View code generated by MVC:
#model IEnumerable<NewsLibrary.Models.StorageModel>
#{
ViewBag.Title = "ViewStorage";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>ViewStorage</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.DateFrom)
</th>
<th>
#Html.DisplayNameFor(model => model.DateTo)
</th>
<th>
#Html.DisplayNameFor(model => model.Size)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateFrom)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateTo)
</td>
<td>
#Html.DisplayFor(modelItem => item.Size)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
I get the following error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[CommonLayer.TblNewsStorage]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[NewsLibrary.Models.StorageModel]'.
The
#model IEnumerable<NewsLibrary.Models.StorageModel>
must have the same datatype passed in.
You are passing in
List<CommonLayer.TblNewsStorage>
If you take a closer look at the Model the View expects you see it's IEnumerable of NewsLibrary.Models.StorageModel. You are passing a list/IEnumerable of the type CommonLayer.TblNewsStorage. Make sure these two are the same datatype.
#foreach (var item in Model) {
item.Name
}
try like this. You need to remove #html.displayfor(model => item.name) to only item.name inside your tags

Categories