Asp.Net MVC3 - How create Dynamic DropDownList - asp.net-mvc-3

I found many articles on this but still I don´t know how exactly to do this. I am trying to create my own blog engine, I have View for create article (I am using EF and Code first) and now I must fill number of category in which article should be add but I want to change it to dropdownlist with names of categories. My model looks this:
public class Article
{
public int ArticleID { get; set; }
[Required]
public string Title { get; set; }
[Required]
public int CategoryID { get; set; }
public DateTime Date { get; set; }
[Required()]
[DataType(DataType.MultilineText)]
[AllowHtml]
public string Text { get; set; }
public virtual Category Category { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
I know I must use Enum (or I think) but I am not exactly sure how. I don´t know which tutorial from that I found is best for me.
Edit:
Thanks for your answers but I found something else. I am trying this:
This is my model:
public class Article
{
[Key]
public int ArticleID { get; set; }
[Display(Name = "Title")]
[StringLength(30, MinimumLength = 5)]
[Required]
public string Title { get; set; }
public DateTime Date { get; set; }
public int CategoryID { get; set; }
[Required()]
[DataType(DataType.MultilineText)]
[AllowHtml]
public string Text { get; set; }
public Category Category { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public IEnumerable<Category> Categories { get; set; }
}
public class Category
{
[Key]
public int CategoryId { get; set; }
[Required]
public string CategoryName { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
This is my controller to create article:
public ActionResult Vytvorit()
{
IEnumerable<Category> categories = GetCaregories();
var view = View(new Article() { Categories = categories });
view.TempData.Add("Action", "Create");
return view;
}
private static IEnumerable<Category> GetCaregories()
{
IEnumerable<Category> categories;
using (BlogDBContext context = new BlogDBContext())
{
categories = (from one in context.Categories
orderby one.CategoryName
select one).ToList();
}
return categories;
}
private Category GetCategory(int categoryID)
{
return db.Categories.Find(categoryID);
}
//
// POST: /Clanky/Vytvorit
[HttpPost]
public ActionResult Vytvorit(Article newArticle)
{
try
{
if (newArticle.CategoryID > 0)
{
newArticle.Category = GetCategory(newArticle.CategoryID);
}
if (TryValidateModel(newArticle))
{
db.Articles.Add(newArticle);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
newArticle.Categories = GetCaregories();
var view = View(newArticle);
view.TempData.Add("Action", "Create");
return view;
}
}
catch
{
return View();
}
}
And this is part of my view:
#Html.DropDownListFor(model => model.CategoryID, new SelectList(Model.Categories,"CategoryID","CategoryName"))
#Html.ValidationMessageFor(model => model.CategoryID)
I have problem with NullReferenceExeption but I don´t know why. Can I do it this way? It looks very easy for me.

Your model seems quite strange. It contains properties such as CategoryID and Category which seem redundant. It also contains a SelectListItem collection property called Categories. So, is this a model or a view model? It looks quite messed up. Let's assume it's a model. In this case it would more likely look something like this:
public class Article
{
public int ArticleID { get; set; }
[Required]
public string Title { get; set; }
public DateTime Date { get; set; }
[Required()]
[DataType(DataType.MultilineText)]
[AllowHtml]
public string Text { get; set; }
public virtual Category Category { get; set; }
public IEnumerable<Category> Categories { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
Now that the model is clear we could define a view model which will be passed to the view. A view model is a class which is specifically designed for the view. So depending on what you intend to put in this view you define it in this view model. So far you have talked only about a drop down, so let's do it:
public class ArticleViewModel
{
public int SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
and then we have a controller:
public class ArticlesController: Controller
{
private readonly IArticlesRepository _repository;
public ArticlesController(IArticlesRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
Article article = _repository.GetArticle();
ArticleViewModel viewModel = Mapper.Map<Article, ArticleViewModel>(article);
return View(viewModel);
}
}
So the controller uses a repository to fetch the model, maps it to a view model (in this example I use AutoMapper) and passes the view model to the view which will take care of showing it:
#model AppName.Models.ArticleViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(
x => x.SelectedCategoryId,
new SelectList(Model.Categories, "Value", "Text"),
"-- Select category --"
)
<input type="submit" value="OK" />
}

I have gone through this as well and I have to agree that at first it seems odd (In my explanation I'm assuming you want to select one category only, but the process is very similar for a multi select).
Basically you need to perform 3 steps:
1:
You need two properties on your viewmodel
One will hold the selected category id (required for postback) and the other will a SelectList with all possible categories:
public class Article
{
public int ArticleID { get; set; }
public int CategoryID { get; set; }
public SelectList Categories { get; set; }
}
2:
Also before passing the viewmodel on to the view you need to initialize the SelectList (Best practivce is to prepare as much as possible before passing a model into the view):
new SelectList(allCategories, "CategoryID", "Name", selectedCategoryID)
3:
In the view you need to add a ListBox for the CategoryID property, but using the Categories property too fill the ListBox with values:
#Html.ListBoxFor(model => model.CategoryID , Model.Categories)
Thats it! In the post back action of the controller you will have the CategoryID set. You can do whatever you need to from there to persist things in your db.

Related

MVC Query expressions over source type 'dynamic' or with a join sequence of type 'dynamic' are not allowed

I am trying to get this expression working in my Razor file:
<span>#($" ({string.Join(", ", from o in comment.CommentStaff.StaffOffices select o.Office.OfficeOrganizationCd)})")</span>
But it says "Query expressions over source type 'dynamic' or with a join sequence of type 'dynamic' are not allowed" in the red squiggly in the Razor and the Developer exception page.
Here is my model (#model CommentVM) coming down to the Razor from the controller action:
public class CommentVM
{
public int AuditId { get; set; }
public string Comment { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
Here is the Controller Action (actually this is coming from the Invoke method in a component. But this shouldn't really make a difference).
public IViewComponentResult Invoke(int auditId)
{
IQueryable<Comment> comments = _commentRepo.Comments.Include(c => c.CommentStaff).ThenInclude(c => c.StaffOffices)
.Where(c => c.CommentAuditId == auditId)
.OrderByDescending(c => c.CommentDate).Take(3);
CommentVM commentVM = new CommentVM
{
AuditId = auditId,
Comments = comments
};
return View(commentVM);
}
The Comments Repo returns an IQueryable of Comment objects.
The Comment POCO looks like this:
[Table("comment")]
public class Comment
{
[Key]
[Column("comment_id")]
public int CommentId { get; set; }
[Column("comment_type_cd")]
public string CommentTypeCd { get; set; }
[Column("comment_audit_id")]
public int? CommentAuditId { get; set; }
[Column("comment_finding_id")]
public int? CommentFindingId { get; set; }
[Column("comment_recommend_id")]
public int? CommentRecommendId { get; set; }
[Column("comment_action_item_id")]
public int? CommentActionItemId { get; set; }
[Column("comment_acd_id")]
public int? CommentAcdId { get; set; }
[Column("comment_pdl_id")]
public int? CommentPdlId { get; set; }
[Column("comment_cost_nm")]
public string CommentCostNm { get; set; }
[Required]
[Column("comment_tx")]
public string CommentText { get; set; }
[Column("comment_dt")]
public DateTime CommentDate { get; set; }
#region Navigation Properties
[Column("comment_staff_id")]
public short CommentStaffId { get; set; }
[ForeignKey("CommentStaffId")]
public Staff CommentStaff { get; set; }
#endregion
}
So CommentStaff is a navigation property to a Staff object which has a bridge table POCO called StaffOffices for a many to many relationship between Staff and Office.
Here is the bridge table POCO:
[Table("staff_office")]
public class StaffOffice
{
[Column("staff_office_staff_id")]
public short ID { get; set; }
public Staff Staff { get; set; }
[Column("staff_office_office_id")]
public short OfficeID { get; set; }
public Office Office { get; set; }
}
I am trying to get this:
<span>#($" ({string.Join(", ", from o in comment.CommentStaff.StaffOffices select o.Office.OfficeOrganizationCd)})")</span>
or this:
#{
StringBuilder sb = new StringBuilder();
foreach(var o in comment.CommentStaff.StaffOffices)
{
sb.Append(o.Office.OfficeOrganizationCd);
}
}
<span>#sb.ToString()</span>
It's a partial view. I needed to include the model definition of the parent Razor file:
#model CommentVM

While filtering, how to POST a SearchModel, but GET a different ResultsModel back in the view

I am creating a filter view to find records. This example on SO helps, but does not mention how handle the (Filtered) View.
The err below is because, the actions returns a List<ProductViewModel>, and it Errors/complains that the View is using a SearchViewModel, I need to this POST the searchmodel/variables, butGET back the list/results model
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[ViewModels.ProductVM]', but this
dictionary requires a model item of type 'ViewModels.SearchModel'.
Issue/Question: Since there are two models, the SearchViewModel passed to the controller & the ProductViewModel returned as a result, which model should be strongly typed to the view? and How can I create the view to handle both SearchModel & ProductModel If I stronglyType ProductVM, then I loose the submitform from the SearchVM.
I create the SearchView as the mainview, & the _ResultsPartialView as a partialView, is this wrong?
public ActionResult Index(SearchModel searchModel)
{
var filteredProdVMList = _Repository.GetFilteredProducts(searchModel);
return View(filteredProdVMList);
}
public class ProductVM
{
public int Id { get; set; }
public int Price { get; set; }
public string Name { get; set; }
// implicit const... blah.. removed
}
public class SearchModel
{
public int? Id { get; set; }
public int? PriceFrom { get; set; }
public int? PriceTo { get; set; }
public string Name { get; set; }
}
You need to modify your SearchModel to include a collection property for the products
public class SearchModel
{
public int? PriceFrom { get; set; }
public int? PriceTo { get; set; }
....
public IEnumerable<ProductVM> Products { get; set; } // add
}
then you return just SearchModel to your view
public ActionResult Filter(SearchModel filter)
{
filter.Products = _repository.GetFilteredProducts(filter);
return View(filter);
}
and your view will be
#model SearchModel
....
#using (Html.BeginForm("Filter", "yourControllerName", FormMethod.Get))
{
#Html.LabelFor(m => m.PriceFrom)
#Html.EditorFor(m => m.PriceFrom)
#Html.ValidationMessageFor(m => m.PriceFrom)
... // other form controls for properties you want to filter the results on
<input type="submit" value="Filter" />
}
#Html.Partial("_ResultsPartialView", Model.Products)

Populating a dropdownlist with values

Hello I'm trying to make my dropdownlist to work but it seems harder than expected. I have 3 domain classes Member, Rental and Movie. My Idea was to make a dropdownlist that will show a specific users rented movies and when I select a movie in the dropdownlist and submit it I will get back the selected movie and I can set bool IsInStock to true.
So I made a viewmodel and a controller action but would like some help how to go forward with this. Now I get a dropdownlist with the users "Jan" rented movies but when I klick submit I would like to get the values back in order to set the IsInStock to true. I know I will need method to handle the POST values but I'm trying to make this work first.
public class Member
{
public virtual int MemberId { get; set; }
public virtual string LastName { get; set; }
public virtual List<Rental> Rentals { get; set; }
}
public class Rental
{
public virtual int RentalId { get; set; }
public virtual int MovieId { get; set; }
public virtual Movie Movie { get; set; }
public virtual int MemberId { get; set; }
public virtual Member Member { get; set; }
}
public class Movie
{
public virtual int MovieId { get; set; }
public virtual string Name { get; set; }
public virtual bool IsInStock { get; set; }
}
public class RentalsViewModel
{
// Need something here.
public IEnumerable<SelectListItem> RentedMovies { get; set; }
}
public ActionResult ReturnMovie()
{
var rentedmovies = db.Rentals.Where(r => r.Member.Name == "Jan").ToList();
var model = new RentalsViewModel()
{
RentedMovies = rentedmovies.Select(x => new SelectListItem
{
Value = x.MovieId.ToString(),
Text = x.Movie.Name
})
};
return View(model);
}
// In the View
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.RentedMovies, //Something here);
<p>
<input type="submit" value="Save" />
</p>
}
First parameter here:
#Html.DropDownListFor(x => x.RentedMovies, //Something here);
must be int, because you will send this value to the server:
public virtual int MovieId { get; set; }
So, your example could look like:
#Html.DropDownListFor(x => x.RentedMovieId, Model.RentedMovies);
(Add property RentedMovieId to RentalsViewModel)

Map a complex MVC ViewModel in knockout

I have a MVC view which contains observables and observablearrays. What is the proper way to map?
My MVC ViewModel looks similar to this:
public class CategorysEditViewModel
{
public Category Categorys { get; set; }
public IEnumerable<Expert> candidates { get; set; }
public IEnumerable<Expert> experts { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Policy { get; set; }
}
public class Expert
{
public int ExpertID { get; set; }
public int CategoryID { get; set; }
public string Name { get; set; }
public string ExpertGUID { get; set; }
}
Assuming the cshtml file is strongly typed to the CategorysEditViewModel, you can serialize the view model object to JSON and then use the ko.mapping tool to map it to a knockout viewmodel.
Check out this post: Best practice on passing Mvc Model to KnockoutJS

Bind dropdown list from database

I have been struggling to create a Dropdown list which will display Country names from database.
The situation is:
I have a Controller "AdvertisementController", a model"AdvertisementModel" and a View "Create.cshtml".
On the view I need to create a dropdown list which will display country names from database.
I know the good thing will be to create a Viewmodel. But how shall I do that?
A bunch of code will be much appreciated. :)
I have the following code but it shows 'null reference' error.
Viewmodel:
public class CommunicationViewModel
{
public string CategoryID { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
}
Model:
public class CreateAdModel
{
[Required]
[Display(Name = "Title")]
public string Title { get; set; }
[Required]
[Display(Name = "Description")]
[DataType(DataType.MultilineText)]
public string Message { get; set; }
[Required]
[Display(Name = "Ad type")]
public string AdType { get; set; }
[Required]
[Display(Name = "Ad category")]
public string AdCategory { get; set; }
public CommunicationViewModel categories { get; set; }
}
Controller:
public ActionResult Index()
{
var query = db.AddCategory.Select(c => new SelectListItem
{
Value = c.ID.ToString(),
Text = c.Name
}
);
var model = new CommunicationViewModel { CategoryList = query.AsEnumerable() };
return View(model);
}
Razor:
#Html.DropDownListFor(m=>m.categories.CategoryID,Model.categories.CategoryList,"--Select one--")
This may help you. Drop down for roles when adding users. very simple tutorial
http://rtur.net/blog/post/2009/06/03/Quick-and-dirty-role-management-in-ASPNET-MVC.aspx

Resources