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"))%>
Related
I have a view which contains a dropdown list and on dropdownlist item being selected I load a partial view. And when the form is submitted I want to be able to get both the values from main view and partial view during form submit.
Here is the main view
#model AdminPortal.Areas.Hardware.Models.CreateModule
#{
ViewBag.Title = "Create Module";
Layout = "~/Views/shared/_BootstrapLayout.basic.cshtml";
}
#Html.ValidationSummary(true)
<fieldset class="form-horizontal">
<legend>Add a Module <small>Create</small></legend>
#using (Html.BeginForm("CreateModule", "Module", new{id="AddModuleForm"}))
{
#Html.ValidationSummary(true)
<div class ="controls">
<div class="input-block-level">#Html.TextBoxFor(model => model.ModuleId, new {#placeholder = "ModuleID"})</div>
<br/>
<div class ="input-block-level" id="selectedModuleTypeName">#Html.DropDownListFor(model => model.SelectedModuleTypeName, Model.TypeNames,"Select Moduletype", new{id = "ModuleList"})</div>
<br/>
<div id="partialDiv"></div>
</div>
<div class="form-actions" id="buttons">
<button type="submit" class="btn btn-primary" id="Submit">Save changes</button>
#Html.ActionLink("Cancel", "ModuleList", null, new { #class = "btn " })
</div>
}
</fieldset>
<div>
#Html.ActionLink("Back to List", "ModuleList")
</div>
<script>
$("#buttons").hide();
$("#ModuleList").on("change", function() {
var modId = $(this).val();
$.get('#Url.Action("GetModulePropertyName", "Module")', { moduleTypeValue: modId }, function(result) {
$("#partialDiv").html(result);
});
//uncomment following section to check if the partial view is working properly
/*.done(function() { alert("done"); })
.fail(function() { alert("fail"); })
.always(function() { alert("completed"); });*/
});
$("#buttons").show();
</script>
and here is the partial view
#model IEnumerable<string>
#foreach(var names in Model)
{
<div class="input-block-level">#Html.TextBoxFor(m=>names, new{Value="", placeholder=names})</div>
<br/>
}
Here is my model
public class CreateModule
{
//Empty form to handle form serialization
public CreateModule()
{
}
[Required]
public string ModuleId { get; set; }
[DataType(DataType.DateTime)]
public DateTime DateEntered { get; set; }
[Required]
public string SelectedModuleTypeName { get; set; }
public IEnumerable<SelectListItem> TypeNames { get; set; }
public List<Property> Properties { get; set; }
}
public class Property
{
public string Name { get; set; }
public string Value { get; set; }
}
Here is the method that script in main view forwards to
[HttpGet]
public ActionResult GetModulePropertyName(string moduleTypeValue)
{
var moduleKindId = _repository.GetModuleKindId(moduleTypeValue);
var modulePropertyNames = _repository.GetModuleKindPropertyNames(moduleTypeValue);
return PartialView("GetModulePropertyName",modulePropertyNames);
}
and finally here is httppost method for the main view
[HttpPost]
public ActionResult CreateModule(CreateModule moduleV)
{
var module = new Module
{
ModuleTypeId = Convert.ToInt64(moduleV.SelectedModuleTypeName),
ModuleId = moduleV.ModuleId,
DateEntered = moduleV.DateEntered,
};
if (ModelState.IsValid)
{
_repository.AddModule(module);
Success("Module added successfully!");
return RedirectToAction("ModuleList", "Module", new {area = "Hardware"});
}
Error("Something went wrong!");
return RedirectToAction("CreateModule", "Module", new { area = "Hardware" });
}
Current situation:
When the form is posted, the properties value of the model that is being passed via partial view is null. I get other values, like typename, Module ID.
What I'd want:
I also want to get the value of properties that is being passed via partial view.
You don't have any input field for the Properties property anywhere in your form. So it will always be null. That's normal.
Here's how you could proceed. Start by setting the correct navigational property so that the helper generates correct names of the corresponding input fields.
Also make sure that you are passing an IEnumerable<Property> model to the partial if you want to be able to get them back correctly:
[HttpGet]
public ActionResult GetModulePropertyName(string moduleTypeValue)
{
var moduleKindId = _repository.GetModuleKindId(moduleTypeValue);
IList<Property> model = ...
return PartialView("GetModulePropertyName", model.ToList());
}
and in your partial view use an editor template:
#model IList<Property>
#{
// This indicates the current navigational context to the helpers
ViewData.TemplateInfo.HtmlFieldPrefix = "Properties";
}
#Html.EditorForModel()
and the last step is to define a custom editor template for the Property class: ~/Views/Shared/EditorTemplates/Property.cshtml (note that the name and location of the template is important)
#model Property
<div class="input-block-level">
#Html.HiddenFor(m => m.Name)
#Html.TextBoxFor(m => m.Value, new { placeholder = Model.Name })
</div>
<br />
Try using the
List<Property>
as a model in your partial view and pass the CreateModule.Properties as model from your View
The problem is model binder can not figure out there
#Html.TextBoxFor(m=>names, new{Value="", placeholder=names})
belongs to as the "names" is not a property on your model class. If you need to bind to the CreateModule.Properties you need to change the partial view to emit textboxes with aproprate names, like this one:
#model IEnumerable<string>
#
{
int i=0;
}
#foreach(var names in Model)
{
<div class="input-block-level">#Html.TextBox("Properties[" + i + "].Value")</div>
<br/>
}
Extension to: How do you handle multiple submit buttons in ASP.NET MVC Framework?
Let us say a view is composed of partial views bound with related models, let's say a student is required to provide multiple contact persons(partial view bound to Person model) and multiple contact numbers(partial view bound to a model) to get registered, sorry for the bad example. Once a contact person or number is added, an action (child postback or whatever) is called which validates the related model (not student model), adds it in a list and returns to the same page for further processing. Once all are added, the parent/master action validates whole student model and processes it.
How to validate the specific model for which an action is being called, add it to the page and return the same student view with added values in response?
This solution uses #2 (Session) since its simpler to code however this demonstrates the principles.
Views
Index View:
#using StackOverflow.Models
<div>
#{ Html.RenderPartial("PersonGrid", Model.Persons, new ViewDataDictionary()); }
#Html.Partial("NewPerson", new Person())
#{ Html.RenderPartial("ContactGrid", Model.Contacts, new ViewDataDictionary()); }
#Html.Partial("NewContact", new Contact())
#using(Html.BeginForm("Validate", "Home", FormMethod.Post))
{
<input type="submit" value="Validate" />
}
</div>
Person Grid
#model IList
<table>
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
</tr>
</thead>
<tbody>
#if (Model != null && Model.Any())
{
foreach (var person in Model)
{
<tr>
<td>#person.FirstName</td>
<td>#person.LastName</td>
</tr>
}
}
else
{
<tr>
<td colspan="2" style="text-align: center">No persons available</td>
</tr>
}
</tbody>
</table>
Contact Grid
#model IList
<table>
<thead>
<tr>
<td>Phone</td>
</tr>
</thead>
<tbody>
#if (Model != null && Model.Any())
{
foreach (var contact in Model)
{
<tr>
<td>#contact.Phone</td>
</tr>
}
}
else
{
<tr>
<td>No contacts available</td>
</tr>
}
</tbody>
</table>
New Person
#model StackOverflow.Models.Person
#using (Html.BeginForm("NewPerson", "Home", FormMethod.Post))
{
<div>
#Html.Hidden("PersonViewState", TempData["PersonViewState"])
#Html.LabelFor(m => m.FirstName)<br />
#Html.TextBoxFor(m => m.FirstName)<br />
<br />
#Html.LabelFor(m => m.LastName)<br />
#Html.TextBoxFor(m => m.LastName)<br />
<br />
<input type="submit" value="Submit" />
</div>
}
New Contact
#model StackOverflow.Models.Contact
#using (Html.BeginForm("NewContact", "Home", FormMethod.Post))
{
<div>
#Html.LabelFor(m => m.Phone)<br />
#Html.TextBoxFor(m => m.Phone)<br />
<br />
<input type="submit" value="Submit" />
</div>
}
Models
public class Person
{
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
}
public class Contact
{
[Display(Name = "Phone")]
public string Phone { get; set; }
}
public class HomeModel
{
public IList<Person> Persons { get; set; }
public IList<Contact> Contacts { get; set; }
}
Helpers
public static class PersistenceMechanism
{
public static IList GetPersons()
{
return (IList<Person>) HttpContext.Current.Session["__Persons"];
}
public static IList GetContacts()
{
return (IList<Contact>) HttpContext.Current.Session["__Contacts"];
}
public static void Update(IList<Person> persons)
{
HttpContext.Current.Session["__Persons"] = persons;
}
public static void Update(IList<Contact> contacts)
{
HttpContext.Current.Session["__Contacts"] = contacts;
}
}
Controller
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new HomeModel
{
Persons = PersistenceMechanism.GetPersons(),
Contacts = PersistenceMechanism.GetContacts()
};
return View(model);
}
[HttpGet]
public ActionResult PersonGrid()
{
var persons = PersistenceMechanism.GetPersons();
return PartialView(persons);
}
[HttpGet]
public ActionResult ContactGrid()
{
var contacts = PersistenceMechanism.GetContacts();
return PartialView(contacts);
}
[HttpPost]
public ActionResult NewPerson(Person model)
{
var persons = PersistenceMechanism.GetPersons() ?? new List<Person>();
persons.Add(model);
PersistenceMechanism.Update(persons);
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult NewContact(Contact model)
{
var contacts = PersistenceMechanism.GetContacts() ?? new List<Contact>();
contacts.Add(model);
PersistenceMechanism.Update(contacts);
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Validate()
{
var persons = PersistenceMechanism.GetPersons();
var contacts = PersistenceMechanism.GetContacts();
// validate
// ...
return RedirectToAction("Index");
}
}
To repeat the question to ensure that I have the idea of what you are asking.
Your page page is build from two partial views with different models. Both of these partial views contain a form which will on submit build a grid of records on the UI. The main page will have a further validate button which will then validate the entire contents of both grids on postback?
In this situation I will like to have two forms where the submit event is powered by Ajax. Either jQuery / Microsoft Ajax. Both forms will submit to two separate actions which will accept their respective models, Person and Contact. Each submit button will return its respective partial view which will be a grid showing the collection of items that have been submitted so far. The partial view returned will update a specified target (e.g. div) since we are using AJAX.
Of course it will be necessary to remember the previous items that were submitted so far in order reconstruct the grid with the new item added. This will mean some soft of persistent storage is required. Some options available are:
Database
Session
Hidden form field(s) (preferred). It is possible to use the array model binding mechanism to support this or a simple serialized object (or list of objects) in a single hidden field.
Validation now becomes simple as the model are available server side through your persistent storage mechanism on postback.
I have the following models:
class A
{
// ...some properties
public B InnerField { get; set; }
}
and
class B
{
public int Id { get; set; }
// ..other properties
}
and a page that has a model Class A and inside the page I have a partial view bound to Class B inside a form.
The value of the Id (in the partial view) is set correctly to the model's Id value (different from 0) but when I submit the page the model has the Id value 0. The Id value is not modified in the component or elsewhere.
Page
...other parts of main page
<%using (Html.BeginForm("ModifyHotel", "Hotel",
FormMethod.Post, new { enctype = "multipart/form-data"}))
{%>
<% Html.RenderPartial("~/Views/Shared/ModifyBaseItem.ascx",
new ModifyItemRequestBaseView() { ItemId = Model.Item.Id });%>
<%}%>
...other parts of main page
Partial View
...other parts of partial view
<br/>
Add Photo: <%:Html.FileBoxFor(x => x.PhotoFile, null)%>
<br/>
Add Video: <%:Html.FileBoxFor(x => x.VideoFile, null)%>
<br/>
<input type="submit" value="Submit changes" />
...other parts of partial view
What can I do to keep the value of the inner model when the post is made?
Thanks,
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
A model = new A() { InnerField = new B() { Id = 5 }};
return View(model);
}
[HttpPost]
public ActionResult Index(B model)
{
//on postback the model should have the value 5 here
return View();
}
}
View:
#model MvcApplication11.Models.A
#using (Html.BeginForm())
{
#Html.Partial("_IndexForm", Model.InnerField)
<input type="submit" />
}
Partial:
#model MvcApplication11.Models.B
#Html.EditorFor(m => m.Id)
I wrote something like this in the controller.
public ActionResult Giris()
{
ViewData["Tarif"] = (from t in _entities.Tarif
join k in _entities.Kullanici on t.KID equals k.KID
select new {KAdi = k.KAdi, TAdi = t.TAdi})
.Take(4);
return View();
}
I am using it as below in the view page.
<% foreach (var item in (IEnumerable<dynamic>)ViewData["Tarif"]) { %>
<div class="begenilen-video" style="float:left">
<img class="video-resmi" alt="reklam" src="../../Uygulama/Resimler/Reklam/1.jpg" />
<span class="benzer-yemek-tarifi-adi"></span><%=item.TAdi %><br />
<span class="benzer-yemek-tarifi-ekleyen">Ekleyen: </span><br />
<span class="benzer-yemek-tarifi-izlenme">İzlenme: </span>
</div>
<% } %>
However,I am receive the error in the select statement.How do I invoke the items in the view page?
Thanks in advance.
As a guess because you haven't posted the error:
The object being stored in ViewData["Tarif"] will be of the type IQueryable<T> where T is an anonymous object and in your view you are casting to IEnumerable<dynamic>. IQueryable is also lazily loaded so you will be trying to execute your query once the object has been disposed.
You should really create a strongly typed view model
public class ViewModelType {
public IEnumerable<TarifType> Tarif { get; set; }
}
Tarif type
public class TarifType {
public string KAdi { get; set; }
public string TAdi { get; set; }
}
controller
public ActionResult Giris() {
var viewModel = new ViewModelType();
viewModel.Tarif = (from t in _entities.Tarif
join k in _entities.Kullanici on t.KID equals k.KID
select new TraifType { KAdi = k.KAdi, TAdi = t.TAdi }
).Take(4)
.ToList();
return View(viewModel);
}
view
<% foreach (var item in viewModel.Tarif) { %>
<div class="begenilen-video" style="float:left">
<img class="video-resmi" alt="reklam" src="../../Uygulama/Resimler/Reklam/1.jpg" />
<span class="benzer-yemek-tarifi-adi"></span><%=item.TAdi %><br />
<span class="benzer-yemek-tarifi-ekleyen">Ekleyen: </span><br />
<span class="benzer-yemek-tarifi-izlenme">İzlenme: </span>
</div>
<% } %>
I don't know if I am explaining this correctly, or if the solution is rather simple, so here goes:
I am using MvcMailer, but before that I set up a wizard input form which I call Quote.cshtml. Behind Quote.cshtml, I set up a model called QuoteModel.cs.
Quote.cshtml at its most basic (I am leaving out all of the wizard logic and only showing one input):
<td width="40%">
#Html.LabelFor(m => m.FirstName, new { #class = "mylabelstyle", title = "Enter first name." })
</td>
<td width="60%">
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(m => m.FirstName)
</td>
QuoteModel.cs (again, only showing the one input; n.b.: using the DataAnnotationExtensions)
public class QuoteModel
{
[Required(ErrorMessage = "First Name required.")]
[Display(Name = "First Name:")]
public string FirstName { get; set; }
}
Now I am trying to integrate MvcMailer, which sets up IQuoteMailer.cs, QuoteMailer.cs, _Layout.cshtml, and QuoteMail.cshtml. The QuoteMail.cshtml is what the recipient of the mail will eventually see. I also set up a QuoteController.cs, in which I placed the appropriate code required by MvcMailer. It is in the QuoteMailer.cs and QuoteController.cs where I am having trouble passing the user input from Quote.cshtml (which is based on the model in QuoteModel.cs).
IQuoteMailer.cs:
public interface IQuoteMailer
{
MailMessage QuoteMail();
}
QuoteMailer.cs:
public class QuoteMailer : MailerBase, IQuoteMailer
{
public QuoteMailer():
base()
{
MasterName="_Layout";
}
public virtual MailMessage QuoteMail()
{
var mailMessage = new MailMessage{Subject = "QuoteMail"};
mailMessage.To.Add("some-email#example.com");
ViewBag.Data = someObject;
//I imagine this is where I can pass my model,
//but I am not sure (do I have to iterate each and
//every input (there are like 20 in QuoteModel.cs)?
return mailMessage;
}
QuoteMail.cshtml (_Layout.cshtml is pretty standard, so not showing here):
#*HTML View for QuoteMailer#QuoteMail*#
Welcome to MvcMailer and enjoy your time!<br />
<div class="mailer_entry">
<div class="mailer_entry_box">
<div class="mailer_entry_text">
<h2>
INSERT_TITLE
</h2>
<p>
INSERT_CONTENT
//I believe I am going to use a "#" command like #ViewData
//to pass FirstName, but again, not sure how to bind
//the model and then pass it.
</p>
<p>
INSERT_CONTENT
</p>
</div>
</div>
</div>
And finally, the relevant parts of the QuoteController.cs (note that I have am using a wizard, therefore, part of my problem is figuring out where to put the MvcMailer code, but I think I may have it right):
public class QuoteController: Controller
{
/// <summary>
/// MvcMailer
/// </summary>
private IQuoteMailer _quoteMailer = new QuoteMailer();
public IQuoteMailer QuoteMailer
{
get { return _quoteMailer; }
set { _quoteMailer = value; }
}
//
// GET: /Quote/
[HttpGet]
public ActionResult Quote()
{
HtmlHelper.ClientValidationEnabled = true;
HtmlHelper.UnobtrusiveJavaScriptEnabled = true;
//In order to get the clientside validation (unobtrusive),
//the above lines are necessary (where action takes place)
return View();
}
//
// POST: /Matrimonial/
[HttpPost]
public ActionResult Quote(QuoteModel FinishedQuote)
{
if (ModelState.IsValid)
{
QuoteMailer.QuoteMail().Send();
return View("QuoteMailSuccess", FinishedQuote);
}
else return View();
}
//
// POST: /Matrimonial/Confirm
[HttpPost]
public ActionResult QuoteMailConfirm(QuoteModel FinishedQuote)
{
return PartialView(FinishedQuote);
}
}
So, my confusion is to how to pass the QuoteModel I created, so that ultimately I can take the user inputed data and then generate the MvcMailer view.
I appreciate the communities help.
You could have the IQuoteMailer interface take the model:
public interface IQuoteMailer
{
MailMessage QuoteMail(QuoteModel model);
}
and in the implementation use this model:
public class QuoteMailer : MailerBase, IQuoteMailer
{
public QuoteMailer() : base()
{
MasterName = "_Layout";
}
public virtual MailMessage QuoteMail(QuoteModel model)
{
var mailMessage = new MailMessage
{
Subject = "QuoteMail"
};
mailMessage.To.Add("some-email#example.com");
// Use a strongly typed model
ViewData = new ViewDataDictionary(model);
PopulateBody(mailMessage, "QuoteMail", null);
return mailMessage;
}
}
then from the controller when you decide to send the mail pass the model:
[HttpPost]
public ActionResult Quote(QuoteModel FinishedQuote)
{
if (ModelState.IsValid)
{
QuoteMailer.QuoteMail(FinishedQuote).Send();
return View("QuoteMailSuccess", FinishedQuote);
}
else return View();
}
and finally in the template (~/Views/QuoteMailer/QuoteMail.cshtml) you could use the model:
#using AppName.Models
#model QuoteModel
Welcome to MvcMailer and enjoy your time!
<br />
<div class="mailer_entry">
<div class="mailer_entry_box">
<div class="mailer_entry_text">
<h2>
INSERT_TITLE
</h2>
<p>
Hello #Model.FirstName
</p>
<p>
INSERT_CONTENT
</p>
</div>
</div>
</div>