MVC Razor DropDownListFor value not set in model - c#

I'm trying to make a razor view that can post a model to my controller.
I've added a dropdown, however platform is always null when i post to my controller.
What am i doing wrong?
This is my view
#using (Html.BeginForm("Register", "Home", FormMethod.Post, new { #class = "form-horizontal", #id = "form" }))
{
#{
var platformList = new List<SelectListItem>() {
new SelectListItem(){ Value="I", Text="iOS"},
new SelectListItem(){ Value="A", Text="Android"},
};
}
<div class="form-group">
#Html.LabelFor(model => model.platform, "Plattform", new { #for = "inputPlatform", #class = "col-lg-3 control-label" })
<div class="col-lg-9">
#Html.DropDownListFor(model => model.platform, platformList, new { #class = "form-control", #id = "inputPlatform" })
</div>
</div>
}
This is my model
public class RegistrationModel
{
public String platform { get; set; }
}
My Controller
[HttpPost]
[AllowAnonymous]
public ActionResult Register(RegistrationModel RegistrationModelViewModel)
{
}

I couldn't get your view to work. There appears to be a formatting issue with the drop down declaration. It has an extra comma and was missing a end }. I kept getting a parse error, which is odd as you say you can get the post to work.
Anyway, I've created an example below which works and so I hope is of some use.
Model
public class RegistrationModel
{
public string platform { get; set; }
}
View
#model TestMVC.Models.RegistrationModel
#using (Html.BeginForm("Register", "Register", FormMethod.Post, new { #class = "form-horizontal", #id = "form" }))
{
var platformList = new List<SelectListItem>() {new SelectListItem(){ Value="I", Text="iOS"}, new SelectListItem(){ Value="A", Text="Android"}};
<div class="form-group">
#Html.LabelFor(model => model.platform, "Plattform", new {#for = "inputPlatform", #class = "col-lg-3 control-label"})
<div class="col-lg-9">
#Html.DropDownListFor(model => model.platform, platformList, new {#class = "form-control", #id = "inputPlatform"})
</div>
</div>
<button type="submit"> Submit</button>
}
Controller
public class RegisterController : Controller
{
[HttpGet]
public ActionResult Register()
{
return View();
}
[HttpPost]
public ActionResult Register(RegistrationModel model)
{
//Do something here;
}
}

Related

One of two model for View is always null in MVC 5

In my MVC5 application I have two model Order and File as following:
public class Order
{
public int OrderID { get; set; }
public string OrderName{ get; set; }
}
public class File
{
public HttpPostedFileBase[] files { get; set; }
}
I want edit objects of both classes in single view, so I create parent class:
public class MainContext
{
public Order Order { get; set; }
public File File { get; set; }
}
In the view I have this:
#using (Html.BeginForm("Create", "Order", FormMethod.Post, new { encType = "multipart/form-data" }))
#Html.AntiForgeryToken()
<div class="form-group">
<label>OrderName</label>
#Html.EditorFor(model => model.Order.OrderName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Order.OrderName, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.LabelFor(model => model.File.files, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.File.files, "", new { #type = "file", #multiple = "multiple", })
#Html.ValidationMessageFor(model => model.File.files, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<input type="submit" value="submit" class="btn btn-success btn-lg btn-block" />
</div>
The Controller
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "OrderName")] Order order, HttpPostedFileBase[] files)
{
if (ModelState.IsValid)
{
db.Order.Add(order);
db.SaveChanges();
if (files != null)
{
foreach (HttpPostedFileBase file in files)
{
if (file != null)
{
var InputFileName = Path.GetFileName(file.FileName);
var ServerSavePath = Path.Combine(Server.MapPath("~/UploadedFiles/") + InputFileName);
file.SaveAs(ServerSavePath);
}
}
}
return RedirectToAction("Index");
}
}
Now the problem .. after I submit the form I got order values in Create action BUT files is always NULL !
What I miss
Thanks in advance
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(MainContext model)
{
// here fetch values from model.Order and model.File
}
Instead of fetching two models separately call "MainContext" class in post action, from that you can get all the view values....

MVC auto validation

I am making my MVC application. I created a view, in which a user picks data from dropdown list. The view is like this:
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#using ClassDeclarationsThsesis.Classes
#using Microsoft.Ajax.Utilities
#model ClassDeclarationsThsesis.Models.ClassesViewModel
#{ ViewBag.Title = "Classes";
}
<h2>Classes</h2>
#foreach (var user in Model.users)
{
if (user.email.Replace(" ", String.Empty) == HttpContext.Current.User.Identity.Name)
{
if (user.user_type.Replace(" ", String.Empty) == 3.ToString() || user.user_type.Replace(" ", String.Empty) == 2.ToString())
{
using (Html.BeginForm("Classes", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Generate summary views</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#{
List<SelectListItem> listItems1 = new List<SelectListItem>();
}
#foreach (var subject in Model.subject)
{
listItems1.Add(new SelectListItem
{
Text = subject.name,
Value = subject.name,
});
}
#Html.LabelFor(m => m.subject_name, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.subject_name, listItems1, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
}
if (user.user_type.Replace(" ", String.Empty) == 1.ToString())
{
<p>You do not have enough permissions to enter this page. Contact the administrator.</p>
}
}
}
The controller is:
public ActionResult Classes()
{
ClassDeclarationsDBEntities1 entities = new ClassDeclarationsDBEntities1();
var model = new ClassesViewModel();
model.subject = entities.Subjects.ToList();
model.users = entities.Users.ToList();
if (ModelState.IsValid)
{
return RedirectToAction("ClassesPickGroup", "Account", new { subject_name=model.subject_name});
}
return View(model);
}
And the model:
public class ClassesViewModel
{
public List<Subject> subject { set; get; }
public List<User> users { get; set; }
[Required]
[Display(Name = "Subject")]
public string subject_name { get; set; }
}
But since the view only contains a single dropdown list, it is always Valid and redirects to different view straight away. How do I make the application wait for user choice in dropdown list and then submit the answer?
There is no problem in your view, but the problem that you create new object every time user submit and check for validation
public ActionResult Classes(ClassesViewModel model)
{
ClassDeclarationsDBEntities1 entities = new ClassDeclarationsDBEntities1();
if (ModelState.IsValid)
{
return RedirectToAction("ClassesPickGroup", "Account", new { subject_name=model.subject_name});
}
else {
model.subject = entities.Subjects.ToList();
model.users = entities.Users.ToList();
return View(model);
}
}

Passing Image to Controller ASP.NET MVC

I am trying to send Image and ImageName from View to Controller.
Here's how my controller looks:
[HttpPost]
public ActionResult Add(BoxAddViewModel image)
{
//TODO: Add new box
return RedirectToAction("Index");
}
This is the model:
public class BoxAddViewModel : BaseViewModel
{
public int Id { get; set; }
[Required]
[DisplayName("Name")]
public string Name { get; set; }
[Required]
[DisplayName("Source")]
public HttpPostedFileBase Source { get; set; }
}
And finally the view:
#using (Html.BeginForm("Add", "BoxManagement", new { #class = "form-horizontal", enctype = "multipart/form-data" }))
{
<div class="form-group">
#Html.LabelFor(m => m.Name, new { #class = "col-sm-2 control-label" })
<div class="col-sm-10">
#Html.TextBoxFor(m => m.Name, new { #class = "form-control", #name = "Name"})
#Html.ValidationMessageFor(m => m.Name)
</div>
#Html.LabelFor(m => m.Source, new { #class = "col-sm-2 control-label" })
<div class="col-sm-10">
<!--Html.TextBoxFor(m => m.Source, new { type = "file",}) -->
#Html.ValidationMessageFor(m => m.Source)
<input type="file" name="Source" id="Source" />
</div>
</div>
<button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-plus"></span>Add</button>
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn btn-default" })
}
It comes into the Add method and the Name property value is correct but the Source is null.
Anyone know how to solve this?
Your using the wrong overload of BeginForm() and adding route values, not html attributes (always inspect the html your generating). Use
#using (Html.BeginForm("Add", "BoxManagement", FormMethod.Post, new { #class = "form-horizontal", enctype = "multipart/form-data" }))
Side note: Remove new { #name = "Name"} from your TextBoxFor() method. Never attempt to override the name attribute generated by the HtmlHelper methods unless you want binding to fail (and is this case it does nothing anyway)

How to create drop down list in Create.cshtml

How to create drop down list in Create.cshtml, where the list is made of data from DB and if there is no such kind of data you want to choose you can enter new value and it saves in DB.
I tried to query from DB to a list and used ViewBag.DropDownList (it worked in Index.cshtml, but not in Create.cshtml, because I was getting error: There is no ViewData item of type 'IEnumerable' that has the key "MyDropDownList")
Create.cshtml:
#using LicenseManager.Models
#model LicenseManager.Models.CompanyNames
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>CompanyNames</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.DropDownList("CompanyNames", (SelectList)ViewBag.DropDownValues)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval") }
and controller CompanyNames.cs:
public class CompanyNamesController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: CompanyNames
public ActionResult Index()
{
ApplicationDbContext db = new ApplicationDbContext();
var querys = from c in db.CompanyNames
select c.Name;
ViewBag.DropDownValues = new SelectList(querys);
return View(db.CompanyNames.ToList());
}
}
Can someone help me with this? I just need some kind of direction where to go, to do. Sorry for the code....
model created :
public class CustomerModel
{
public List<SelectListItem> ListAdCode { get; set; }
}
Create a function to bind a list :
public static List<SelectListItem> AdCodeList()
{
List<SelectListItem> list = new List<SelectListItem>();
list.Add(new SelectListItem { Text = "--Select--", Value = null, Selected = true });
using (CrmKolmEntities entities = new CrmKolmEntities())
{
var allActiveCAdCodes = entities.AdCodes.Where(x => x.IsDeleted == false).ToList();
if (allActiveCAdCodes.Count() > 0)
{
foreach (var adCode in allActiveCAdCodes)
{
list.Add(new SelectListItem { Text = adCode.AdCodeName, Value = adCode.AdCodeId.ToString() });
}
}
}
return list;
}
On Controller :
public ActionResult ManipulateCustomer(int id, int? idOrder)
{
CustomerModel model = new CustomerModel();
model.ListAdCode = AdCodeList();
if (model.ListPriceList == null)
{
model.ListPriceList = CommonFunctions.PriceListActive(null);
}
return View(model);
}
On View:
#Html.DropDownListFor(r => r.AdCodeId, new SelectList(Model.ListAdCode, "value", "text", "selectedValue"), new { #class = "input", #style = "width:450px" })
I think you need Html.DropDownList instead of ViewBag.DropDownList. The former is from the HtmlHelper class and I think it's what you need. You can read more about it here.

Using same partial view for edit and new operations

.NET 4.51, MVC 5
I have a view Edit.cshtml as follows:
#model EnergyMission.Country.Dtos.GetCountryOutput
#{
ViewBag.Title = "Edit Country";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Html.Partial("_AddEditPartial", new ViewDataDictionary { { "ActionName", "Edit" } })
and then New.cshtml as follows:
#model EnergyMission.Country.Dtos.GetNewCountryOutput
#{
ViewBag.Title = "New Country";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Html.Partial("_AddEditPartial", new ViewDataDictionary { { "ActionName", "Create" } })
Note from the above that:
Each one has a different model namely GetCountryOutput and GetNewCountryOutput. Both of these have the same properties. Currently they cannot be made the same class for other reasons.
I pass the action name so that I can use it in the Html.BeginForm in the partial view
I still need to figure out how to pass the model type to the partial view
The _AddEditPartial.cshtml looks as follows:
#model EnergyMission.Country.Dtos.GetCountryOutput
<h3>#ViewData["ActionName"]</h3>
#using (Html.BeginForm(#ViewData["ActionName"], "Countries"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>CountryTableModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.AbbreviationCode, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.AbbreviationCode, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.AbbreviationCode, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.InternationalCountryDialCode, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.InternationalCountryDialCode, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.InternationalCountryDialCode, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
</div>
}
My questions are as follows:
Is there an easier way to share a common data entry layout for Add / Edit operations that whay I am doing above?
If I were to follow the approach described how do I:
Pass the model type to the partial view. Is it something like:
_
#Html.Partial("_AddEditPartial", new ViewDataDictionary { { "ActionName", "Create" }, {"ModelTypeName", "EnergyMission.Country.Dtos.GetCountryOutput"} })
and then in _AddEdit.cshtml
_
#model typeof(#ViewData["ModelTypeName"])
Why is the following not valid:
_
#using (Html.BeginForm(ViewData["ActionName"], "Countries"))
as that gives me a compile time error.
Create a single view, then use your controller to direct to a single view and use your repository to insert/update accordingly in a Save method. However, please note, in the example below you will need to make sure the model is the same - based on the principle that you should remove duplication. If that's not possible consider using a dynamic model in your view or using the ViewModel you can map the properties accordingly (anyway I don't want to over complicate the answer as I'm hoping this provides the solution you need - give or take some refactoring here and there).
A simplified example of the controller and repository (using a viewmodel)....
public class ProductController : Controller
{
private IProductRepository _repository;
public ProductController(IProductRepository productsRepository)
{
this._repository = productsRepository;
}
public ViewResult Edit(int productID)
{
ProductEditViewModel model = new ProductEditViewModel
{
Product = this._repository.Products.Where(m => m.ProductID == productID).FirstOrDefault()
};
return View(model);
}
[HttpPost]
public ActionResult Edit(int productId)
{
ProductEditViewModel model = new ProductEditViewModel
{
Product = _repository.Products.First(m => m.ProductID == productId)
};
TryUpdateModel(model);
if (ModelState.IsValid)
{
_repository.Save(model.Product);
return RedirectToAction("Index");
}
else
{
return View(model);
}
}
public ViewResult Create()
{
return View("Edit", new Product());
}
[HttpPost]
public ActionResult Create(Product product)
{
return Edit(product.ProductID);
}
}
The repository....
public class SqlProductRepository : IProductRepository
{
private MyDataContext db;
private Table<Product> _productsTable;
public IQueryable<Product> Products
{
get { return _productsTable; }
}
public void Save(Product product)
{
if (product.ProductID == 0)
{
_productsTable.InsertOnSubmit(product);
}
else if (_productsTable.GetOriginalEntityState(product) == null)
{
_productsTable.Attach(product);
_productsTable.Context.Refresh(RefreshMode.KeepCurrentValues, product);
}
_productsTable.Context.SubmitChanges();
}
}
Well the answer to 3. is that html.beginform expects a string as its first parameter, and as you are using ViewData which is a
Dictionary<string, object>
you need to cast your value as a string:
#using (Html.BeginForm(ViewData["ActionName"] as string, "Countries"))
For 1. You could try deriving both of your dto classes from a base class and setting that class as the model type for both the add and edit views

Categories

Resources