Display a view with many to many relationship - asp.net-mvc

Having problem to display a generic list with books and its authors at view state.
A book can have one, two or three authors.
How shall I display a list that contains many books with right authors in view level?
// Fullmetalboy
The following tables of the database is:
Bok (eng. Book)
BokID
Titel
Styckpris
Sammanfattning
Bok_Forfattare (eng. Book_Author)
Bok_ForfattareID
BokID
ForfattareID
Forfattare (eng. Author)
ForfattareID
Fornamn
Efternamn
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<BokButik1.ViewModels.SokningPerformSearchViewModel>"
%>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent"
runat="server">
PerformSearch
<h2>Sökresultat</h2>
<table>
<% foreach (var bok in Model.Boks) { %>
<tr>
<td><%: bok.Titel %> av <%: bok.Bok_Forfattare %></td>
<td rowspan="2"><%: bok.Kategori.KategoriNamn %></td>
<td rowspan="2"><div id="Div1"><input type="submit"
value="+ Add to cart" />
<%: bok.Sammanfattning %>
..
<% } %>
</table>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult PerformSearch(string txtSearch, Kategori kategoriNummer)
{
Search test = new Search(txtSearch, kategoriNummer);
var asdf = test.HamtaBokListaFranSokFunktion();
var results = new SokningPerformSearchViewModel
{
Boks = asdf,
Bok_Forfattares = myIBok_ForfattareRepository.HamtaAllaBok_ForfattareNummer()
};
return View(results);
}
namespace BokButik1.ViewModels
{
public class SokningPerformSearchViewModel
{
public List<Bok> Boks { get; set; }
public List<Bok_Forfattare> Bok_Forfattares { get; set; }
}
}

I would split your ViewModel into two ViewModels:
public class SokningPerformSearchViewModel
{
public IList<BookSearchResultViewModel> Boks { get; set; }
}
public class BookSearchResultViewModel
{
public IList<Bok> Boks { get; set; }
public IList<Bok_Forfattare> Bok_Forfattares { get; set; }
}
For every book returned in the search results, create a new BookSearchResultViewModel and assign the book to Boks. Then fetch the authors and attach them to Bok_Forfattares. Next, add that book into your SokningPerformSearchViewModel.Boks list. Finally, return the SokningPerformSearchViewModel to your View.

Related

ASP MVC - How use two models in one single view

I have a web page that have two task
1) add new products
2) display existing products in a table (refer below image)
also i have two classes for each above task
for display existing details and save new product
public class VMProduct
{
public List<Product>ProductList { get; set; }
}
public class Product
{
public String ProductID { get; set; }
public String ProductName { get; set; }
public String Uom1 { get; set; }
public String Uom2 { get; set; }
public String ProductCategoryID { get; set; }
}
my problem is i can display data by using VMProduct.ProductList model but how i can save new product items using "product" model ?
how can i use both Models in One view?
if i use "product" model's properties in VMProduct model it is duplication codes right?
can anyone have a Solution for this?
thanks in advance
It looks like VMProduct is already a custom view model (I'm mostly guessing by its name), so just add a property to it of the type you need:
public class VMProduct
{
public List<Product> ProductList { get; set; }
public Product NewProduct { get; set; }
}
Though, unless I'm misunderstanding something about your UX, this might not even be necessary. The model used to render a view doesn't necessarily need to be the same model received from any given form on that view. So you might continue to render the view using the VMProduct object you have now, and the form for adding a product can still post an instance of Product to the controller action which invokes the add operation. Something like:
public ActionResult Add()
{
// create your view model
return View(someVMProduct);
}
[HttpPost]
public ActionResult Add(Product newProduct)
{
// add the product to the backing data store
return RedirectToAction("Add");
}
Here explained how to implement 2 model in 1 view in MVC 4. Sometimes its required to implement a page where 2 forms exist in a single view (page) like Login & Registration in a same view.
You can get complete tutorial here : http://dotnetawesome.blogspot.com/2013/09/2-model-in-1-view-in-mvc-4.html
Here is the sample code :
A ViewModel Created :
public class UsersLoginRegister
{
public User User { get; set; }
public Login Login { get; set; }
}
User Entity
public partial class User
{
public int UserID { get; set; }
[Required]
public string Username { get; set; }
[Required]
[DataType(System.ComponentModel.DataAnnotations.DataType.Password)]
public string Password { get; set; }
[Required]
public string FullName { get; set; }
}
Login Entity
public class Login
{
[Required]
public string UserName { get; set; }
[Required]
[DataType( System.ComponentModel.DataAnnotations.DataType.Password)]
public string Password { get; set; }
}
In the view (Html) code :
<table>
<tr>
<td><b>Login</b></td>
<td><b>Register</b></td>
</tr>
<tr>
<td>
#using (Html.BeginForm("Login", "Home", FormMethod.Post))
{
<table>
<tr>
<td>Username : </td>
<td>#Html.TextBoxFor(a => a.Login.Username)</td>
</tr>
<tr>
<td>Password : </td>
<td>#Html.EditorFor(a => a.Login.Password)</td>
</tr>
<tr>
<td></td>
<td> <input type="submit" value="Submit" /></td>
</tr>
</table>
}
</td>
<td>
#using (Html.BeginForm("Register", "Home", FormMethod.Post))
{
<table>
<tr>
<td>Fullname : </td>
<td>#Html.TextBoxFor(a => a.User.FullName)</td>
</tr>
<tr>
<td>Username : </td>
<td>#Html.TextBoxFor(a => a.User.Username)</td>
</tr>
<tr>
<td>Password : </td>
<td>#Html.EditorFor(a => a.User.Password)</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="Submit" />
</td>
</tr>
</table>
}
</td>
</tr>

List is not persisting through updatemodel

My generic list of products won't persist on the Post if I use UpdateModel but if I pass the ViewModel in as a parameter to my post action method it works? How can I get it to work through UpdateModel way?
I'm using asp.net fx3.5 mvc 1.0
Model
namespace PostingGenericListAndUpdateModel.ViewModels
{
public class Product
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class ProductViewModel
{
public int OrderId { get; set; }
public List<Product> Products { get; set; }
public ProductViewModel()
{
Products = new List<Product>();
Products.Add(new Product() { Name = "Widget 1", IsSelected = false });
Products.Add(new Product() { Name = "Widget 2", IsSelected = false });
}
}
}
View
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Index</h2>
<% using (Html.BeginForm())
{ %>
<% for (int i = 0; i < 2; i++)
{ %>
<%= Model.Products[i].Name %> <%= Html.CheckBox("Model.Products[" + i + "].IsSelected") %>
<% } %>
<input id="Submit1" type="submit" value="submit" />
<% } %>
</asp:Content>
Controller
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
ProductViewModel model = new ProductViewModel();
return View(model, new string[] { "OrderId", "Products" });
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection form) //It will work if i accept the view model
{
ProductViewModel model = new ProductViewModel();
UpdateModel(model);
return View(model);
}
I see no reason for this parameter 'string sender'. Why do you need it?
The usual way to do this is indeed, by accepting the view model as a parameter to your Post method.
This is the way MVC passes the information from the view to your controller.
Your Post method line should be:
public ActionResult Index(ProductViewModel model)

ASP.NET mvc : HOWTO: Update database after editing multiselectlist (listbox)

I'm really stuck at this: I have two listboxes populated from a database. I want to copy items from one list to the other. Then the changes must be saved in the database.
This is what I've got:
Custom ViewModel:
public class StudentModel
{
public IEnumerable<SelectListItem> NormalStudentsList { get; set; }
public IEnumerable<SelectListItem> StudentsNoClassList { get; set; }
public string[] NormalSelected { get; set; }
public string[] NoClassSelected { get; set; }
public string Save { get; set; }
}
Controller:
public ActionResult IndexStudents(Docent docent, int id, int klasgroepid)
{
var studentModel = new StudentModel
{
NormalStudentsList = docent.GeefStudentenNormaalList(id, klasgroepid),
StudentsNoClassList = docent.GeefStudentenNoClassList(id, klasgroepid)
};
return View(studentModel);
}
[HttpPost, Authorize]
public ActionResult IndexStudentsResult(StudentModel model, string add, string remove)
{
ModelState.Clear();
(if! string.IsNullOrEmpty(add))
//update database
SaveState(model);
return View(model);
}
But how can I update the database?? Using UpdateModel()?
or should I work with FormCollection? But I need a formCollection to work with UpdateModel()...
The Students table has a field named "ClassID", and when copying the rows from 1 list to the other, the ID has to change from the current ClassID to "0".
How can I do that? I'm really stuck at this... hope you can help.
This is my View
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ProjectenII.Models.Domain.StudentModel>"%>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
IndexStudents
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>IndexStudents</h2>
<%using (Html.BeginForm()) { %>
<%=Html.ListBoxFor(model => model.NormalSelected, new MultiSelectList(Model.NormalStudentsList, "StudentNummer", "Naam", Model.NormalSelected), new { size = "6" }); %>
<input type="submit" name="add"
id="add" value=">>" /><br />
<%=Html.ListBoxFor(model => model.NoClassSelected, new MultiSelectList(Model.StudentsNoClassList, "StudentNummer", "Naam", Model.NoClassSelected)); %>
<% } %>
<%=Html.HiddenFor(model => model.Save) %>
<input type="submit" name="apply" id="apply" value="Save!" />
</asp:Content>
Your problem is related to returning a List from the view... check this post by Phil Haack:
Model Binding To A List
Here you can see I ran into a similar problem. In my case a used checkboxes to select items in a list. The solution proposed guided me in the right direction but it wasn't the one I used, I used Phil's post.
My Post
Hope this helps.
We may also achieve using Editor helper, but making all of the multiselectlist elements selected before submit will work:
$("#NormalSelected option").prop("selected", true);
This will pass multiselectlist items to controller.

Display a customized dropdownlist

I have problem to display names of different category as a dropdownlist + display a general name that is a selection of every category. I need this in order to create a search function.
The orginal categori List is:
Datorer & IT
Filosofi & Religion
Sport & Fritid
Djur & Natur
Konst & Musik
Psykologi & Pedagogik
The request to display as dropdownlist:
All Category
Datorer & IT
Filosofi & Religion
Sport & Fritid
Djur & Natur
Konst & Musik
Psykologi & Pedagogik
<%# Import Namespace="BokButik1"%>
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Edit Album</legend>
<%: Html.DropDownList("KategoriID", new SelectList(ViewData["Kategoris"] as IEnumerable, "KategoriID", "KategoriNamn", Model.Kategoris))%>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
namespace BokButik1.ViewModels
{
public class SokningIndexViewModel
{
public List<Kategori> Kategoris { get; set; }
}
}
namespace BokButik1.Controllers
{
public class SokningController : Controller
{
private IKategoriRepository myIKategoriRepository = new KategoriRepository();
//
// GET: /Sokning/
public ActionResult Index()
{
var SokningIndexViewModel = new SokningIndexViewModel
{
Kategoris = myIKategoriRepository.HamtaAllaKategoriNamn()
};
return View(SokningIndexViewModel);
}
}
}
Just add a new Kategori item to the beginning of your list, however it appears you may also be mixing your Model and ViewData up
public ActionResult Index()
{
var SokningIndexViewModel = new SokningIndexViewModel()
{
Kategoris = myIKategoriRepository.HamtaAllaKategoriNamn();
};
//add the 'all catagory' item
SokningIndexViewModel.Kategoris.Insert(0, new Kategori() {
KategoriID = 0,
KategoriNamn = "All Category"
});
return View(SokningIndexViewModel);
}
In your view
<%: Html.DropDownList("KategoriID", new SelectList(Model.Kategoris as IEnumerable, "KategoriID", "KategoriNamn"))%>

How to assign multiple models to a single view?

I have a list of cities and a list of countries and both of them I want to have on the view (aspx) file. I'm trying something like this but it's not working:
namespace World.Controllers {
public class WorldController : Controller {
public ActionResult Index() {
List<Country> countryList = new List<Country>();
List<City> cityList = new List<City>();
this.ViewData["CountryList"] = countryList;
this.ViewData["CityList"] = cityList;
this.ViewData["Title"] = "World Contest!";
return this.View();
}
}
}
<table>
<% foreach (Country country in this.ViewData.Model as IEnumerable) { %>
<tr>
<td><%= country.Code %></td>
</tr>
<% } %>
</table>
You need to get the view data you've set by name. I.E.
<table>
<% foreach (Country country in (List<Country>)this.ViewData["CountryList"]) { %>
<tr>
<td><%= country.Code %></td>
</tr>
<% } %>
</table>
But that's not ideal, because it's not strongly typed. What I would suggest is creating a model specific to your view.
public class WorldModel
{
public List<Country> Countries { get; set; }
public List<City> Cities { get; set; }
}
And then creating your view strongly typed as a WorldModel view. Then in your action:
List<Country> countryList = new List<Country>();
List<City> cityList = new List<City>();
WorldModel modelObj = new WorldModel();
modelObj.Cities = cityList;
modelObj.Countries = countryList;
this.ViewData["Title"] = "World Contest!";
return this.View(modelObj);
Just make sure that your view is strongly typed:
public partial class Index : ViewPage<WorldModel>
And you'll be able to do it this way:
<table>
<% foreach (Country country in ViewData.Model.Countries) { %>
<tr>
<td><%= country.Code %></td>
</tr>
<% } %>
</table>

Resources