Retrieve Value Partial View and Pass to Controller - c#

I have a partial view that allows a user to select a customer. When the user selects the customer they will clock on the LoadConfiguration button in the view.
I want the view to pass the selected customer to the controller action method so that I can use it in my logic when loading the files.
Can someone advise the best way to do this my code so far is below:
Partial View
#model Mojito.Models.Customer
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.CustomerId, "Customer", new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.DropDownList("CustomerId", String.Empty)
#Html.ValidationMessageFor(model => model.CustomerId)
</div>
</div>
</div>
}
View
#using Mojito.Models
#model Mojito.Models.MojitoXmlConfiguration
#{
ViewBag.Title = "Mojito Load Config";
}
<div>#Html.Partial("~/Views/Shared/_Customer.cshtml")</div>
#using (Html.BeginForm("Load", "MojitoXmlConfiguration", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<input type="submit" value="Load Mojito Configuration" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Controller
using System.Web.Mvc;
using Mojito.Models;
namespace Mojito.Controllers
{
public class MojitoXmlConfigurationController : Controller
{
private MojitoContext _db = new MojitoContext();
//
// GET: /MojitoXmlConfiguration/
public ActionResult Index()
{
ViewBag.CustomerId = new SelectList(_db.Customers, "CustomerId", "CustomerName");
return View();
}
[HttpPost]
public ActionResult Load()
{
var mojitoXml = new MojitoXmlConfiguration.Importer(#"C:\Users\Documents\XML Files\SampleList");
mojitoXml.ImportWsaHolidayUsingXElement();
ViewBag.CustomerId = new SelectList(_db.Customers, "CustomerId", "CustomerName");
return View("Index");
}
}
}

Based on your setup, it looks like your partial view will POST back to the Index action. I would add another action method like so
[HttpPost]
public ActionResult Index(int CustomerId)
{
//process
Return View("Load")
}

Related

Passing selected string from dropdown to controller

I am displaying a dropdown list from my controller as follows:
public ActionResult Index()
{
var title = new List<String>()
{
"English", "French", "Spanish"
};
List<SelectListItem> languageList = new List<SelectListItem>();
string defaultTitle = "Language";
foreach (var item in title)
{
languageList.Add(new SelectListItem()
{
Text = item,
Value = item,
Selected = (item == defaultTitle ? true : false)
});
}
ViewBag.LanguageList = languageList;
return View();
}
My View is as follows:
#using (Html.BeginForm("GetStatusTrad", "StatusTradController", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Translation</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.Label("Language")
#Html.DropDownList("lang", new SelectList(ViewBag.LanguageList, "Text", "Value"), "Language")
</div>
</div>
<div></div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
It displays the dropdown correctly, but when I want to pass the selected value to an action of the controller, I get a 404 error.
My action is :
public ActionResult GetStatusTrad(string language)
{
*some code*
}
Any idea why I can't pass the selected value of the dropdown to the controller?
Your helper should be:
#Html.DropDownList("language", <-- note this
new SelectList(ViewBag.LanguageList, "Text", "Value"), "Language")
It happend becose basically your helper will be rendered to input like this:
<select name="language">
...
</select>
And on form POST your controller will be able to bind your values based on name property of input.
#Html.DropDownList("lang", new SelectList(... generates a <select> with name="lang. You need to change the parameter in the POST method to match
public ActionResult GetStatusTrad(string lang)
As a side note, LanguageList is already IEnumerable<SelectListItem> so using new SelectList() to create another identical one is pointless. I can be just
#Html.DropDownList("lang", (IEnumerable<SelectListItem>)ViewBag.LanguageList, "Language")
You also have a typo in the BeginForm() method. It needs to be
#using (Html.BeginForm("GetStatusTrad", "StatusTrad", FormMethod.Post))
i.e. "StatusTrad", not "StatusTradController" (unless you have really named your controller StatusTradControllerController)
you can use strongly type view to return selected dropdown value.
create simple class like below
public class myModel
{
public string language { get; set; }
....
....
}
Then use this class/model in View
#model yourProject.Models.myModel
<div class="form-group">
<label class="col-lg-2 control-label">Language</label>
<div class="col-lg-5">
#Html.ValidationMessageFor(m => m.language)
#Html.DropDownListFor(m => m.language, new SelectList(ViewBag.LanguageList, "Text", "Value"), "-- Select --", new { #class = "form-control" })
</div>
</div>
Controller method look like below
[HttpPost]
public ActionResult GetStatusTrad(myModel model)
{
*some code*
}

How to handle multiple dynamic form with c#

I want to have a page on my website where I can upload files. For each file I want to have a name and a category.
[Required(ErrorMessage = "Please choose a file")]
[Display(Name = "File")]
public HttpPostedFileBase file { get; set; }
[Required(ErrorMessage = "A name is required")]
[Display(Name = "Name")]
public string name { get; set; }
[Display(Name ="Category")]
public string cat { get; set; }
This is my model. I want to have some dynamic form, what I mean is a form with a button that allows the user to add another form on the page to upload multiple files with a name and a category for each file. I've done this with Symfony2, but I have no idea how to do it with ASP.NET. Can someone help me please ?
At first create another model like following:
public class fileListModel{
IList<yourModel> fileList {get;set;}
}
Then in the razor view create form like this way:
#model fileListModel
<form>
//dynamic html(you can also use partial for this). When button will be clicked append following html using jquery $(form).append()
#{var key = [use some random id or guid]}
<input type="hidden" name="fileList.Index" value="#key" />
<input type="text" name="fileList[#key].name" value="Name" />
<input type="text" name="fileList[#key].cate" value="Category" />
<input type="file" name="fileList[#key].file" value="Upload"/>
// end dynamic html
#{ key = [use some random id or guid]}
<input type="hidden" name="fileList.Index" value="#key" />
<input type="text" name="fileList[#key].name" value="Name" />
<input type="text" name="fileList[#key].cate" value="Category" />
<input type="file" name="fileList[#key].file" value="Upload"/>
// end dynamic html
</form>
Now create a controller action method to accept the fileList:
public ActionResult upload(fileListModel fileList){
//save them to db
}
The following is a bare minimum example based on this blogpost. For demo purposes, I've named my model Foo. So whenever you read this, this should be your model with file, name and cat properties.
First, add https://www.nuget.org/packages/BeginCollectionItem/ to your project.
Then, add a partial view to your Views folder. I've named mine "_AddFile.cshtml":
#model WebApplication2.Models.Foo
#using (Html.BeginCollectionItem("files"))
{
<div class="form-horizontal">
<fieldset>
<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" } })
</div>
#Html.LabelFor(model => model.Cat, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Cat, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
</fieldset>
</div>
}
Note, the Html.BeginCollectionItem("files"), this is creating a collection, that is later grouped together and bound to your model named "files".
Our controller looks like this:
public ActionResult Index()
{
//Initialize the view with an empty default entry
var vm = new List<Foo> {
new Models.Foo {
Cat ="foo",
Name =" bar"
}
};
return View(vm);
}
//this calls your partial view and initializes an empty model
public PartialViewResult AddFile()
{
return PartialView("_AddFile", new Foo());
}
//note "files" name? The same as our collection name specified earlier
[HttpPost]
public ActionResult PostFiles(IEnumerable<Foo> files)
{
//do whatever you want with your posted model here
return View();
}
In your view, use this form:
#model IEnumerable<WebApplication2.Models.Foo>
#using (Html.BeginForm("PostFiles","Home", FormMethod.Post))
{
<div id="FileEditor">
#foreach (var item in Model)
{
Html.RenderPartial("_AddFile", item);
}
</div>
<div>
#Html.ActionLink("Add File", "AddFile", null, new { id = "addFile" }) <input type="submit" value="Finished" />
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script>
$(function () {
$("#addFile").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) { $("#FileEditor").append(html); }
});
return false;
});
})
</script>
}
The foreach loop renders a partial View for each model entry, in our case just one with a default entry.
The javascript loop then calls our PartialView and renders an empty template below the existing ones.
A call to submit, then lets you deal with your files in any way you want:

MVC submit form more than once

I have come across a weird issue, I hope someone can explain why the following is happening.
My controller:
MasterModel main = new MasterModel();
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult VehicleDetail()
{
pageSessionSetup();
return PartialView("VehicleDetail", main.Vehicle);
}
[HttpPost]
public ActionResult VehicleDetail(VehicleDetailDisplay model)
{
ModelState.AddModelError("", "Errors occured");
main.Vehicle = model;
pageSessionSetup();
return PartialView("VehicleDetail", main.Vehicle);
}
Updated With View
My View:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
#using (Ajax.BeginForm("VehicleDetail", "Operator", null, new AjaxOptions
{
UpdateTargetId = "VehicleDetail",
InsertionMode = InsertionMode.Replace,
HttpMethod = "Post"}, new { id = "VehicleDetail" }))
{
#Html.Partial("_ValidationSummary", ViewData.ModelState)
<div class="panel panel-default panel-body">
...
</div>
<div class ="col-lg-7 col-md-7 col-sm-7 col-xs-7 row">
<button type="submit" value="Save" class="btn btn-lg btn-green col-lg-2 col-md-5 col-sm-7 col-xs-7">Save</button>
</div>
}
And on my partial view I have a submit button, but when I click the submit button one time then the form gets submitted more than one time.
UPDATE:
use Html.BeginForm("ActionName", "ControllerName", FormMethod.Post) instead of Ajax.BeginForm() OR check if you have included the jquery.unobtrusive-ajax.min.js twice in your page(s)(in partial views also).
--------------------------------------------------------------------------------------------------------
#using (Html.BeginForm("ActionName", ""ControllerName", FormMethod.Post))
{
<label>SomeLabel</label>
...
<input type="submit" value="Button" /></p>
}

How to solve conflict between two models, one in template and other in a View in ASP.NET MVC

I am having problems when I have a model in my navigation partial and a model in my registration view (which of course is in #RenderBody()
This is the error I am getting
The model item passed into the dictionary is of type 'ProfessionalDev.Models.Registration', but this dictionary requires a model item of type 'ProfessionalDev.Models.Login'.
Line 14: <body>
Line 15:
Line 16: #Html.Partial("_Navigation") <=== THE ERROR IS HERE
Line 17: <div class="top-bg"></div>
Line 18: <div class="container body-content">
My layout if as follows
#Html.Partial("_Navigation")
<div class="top-bg"></div>
<div class="container body-content">
#Html.Partial("_Header")
<main>
#RenderBody()
</main>
<footer>
<p>Copyright © 2009-#DateTime.Now.Year Company</p>
</footer>
</div>
The _Navigation partial where I have a Login model because of the Login form
#model ProfessionalDev.Models.Login
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
...
<ul class="dropdown-menu">
<li>
#Html.Partial("_Messages")
#using (Html.BeginForm("Index", "Home", FormMethod.Post)) {
#Html.ValidationMessageFor(model => model.Email)
#Html.TextBoxFor(model => model.Email, new { #class = "form-control", #placeholder = "Email" })
#Html.ValidationMessageFor(model => model.Passwd)
#Html.PasswordFor(model => model.Passwd, new { #class = "form-control", #placeholder = "Password" })
<input type="submit" value="Submit" name="action:Login" class="btn btn-primary btn-sm" />
}
</li>
<li role="separator" class="divider"></li>
<li>Forgot Password?</li>
</ul>
...
Then I have the Registration view with a Registration model
#model ProfessionalDev.Models.Registration
#{
ProfessionalDev.Library.IdentifierTypeItems identifierTypes = new ProfessionalDev.Library.IdentifierTypeItems();
}
<h1>New User Account</h1>
<hr />
#using (Html.BeginForm("Index", "Registration", FormMethod.Post)) {
<div class="row">
<div class="col-md-6">
<div class="form-group">
#Html.LabelFor(model => model.FirstName, "First Name", new { #class = "control-label" }) <span class="required">* </span>
#Html.ValidationMessageFor(model => model.FirstName)
#Html.TextBoxFor(model => model.FirstName, new { #class = "form-control" })
</div>
...
<input type="submit" value="Register" name="action:Register" class="btn btn-primary" />
}
RegistrationController
public class RegistrationController : Controller
{
// GET: Registration
public ActionResult Index()
{
return View();
}
[HttpPost]
[MultipleButton(Name = "action", Argument = "Register")]
public ActionResult Index(Registration reg) {
if (ModelState.IsValid) {
...
return RedirectToAction("Index", "Home");
}
return View("Index", reg);
}
}
When I click the Register button and the Registration object is invalid, as you can see above is supposed to return reg to the Registration/Index view, but instead is returning the view to the Home/Index view from the _Navigation partial
HomeController
public class HomeController : Controller
{
[HttpPost]
[MultipleButton(Name = "action", Argument = "Login")]
public ActionResult Index(Login login)
{
...
return View("Index", login);
}
(I hope I am making sense...)
How can I fix this?
This is how it looks from GUI. The Login in the top menu and the register page
You get redirected to because you using #using (Html.BeginForm("Index", "Home", FormMethod.Post)) inside your main view and doesn't matter what is inside your partial view.
Besides, Only way you could call partial view method inside a main view is jQuery.
The best approach is using a ProfessionalDev.Models.Login type property inside your ProfessionalDev.Models.Registration.
Then use your Html.BeginForm for login inside the registration view.

I can't send my model in my controller

I have a problem to send my Model into my controller.
I use a button with the ajax to change the page but i need the model who is the first page to the second page.
I would like send my model in my controller but it's not work.
When i come in the page CreateAll, the renderpartial follow works to display Step1 but if i click on the step2 i would like the mainModel to be send to my controller use a partial view with submodel.
My model is:
public class CreateAllStep
{
public CreateStep1 Step1 { get; set; }
public CreateStep2 Step2 { get; set; }
public CreateAllStep(CreateStep1 step1, CreateStep2 step2)
{
this.Step1 = step1;
this.Step2 = step2;
}
}
My controller is(when the page start):
public ActionResult Create()
{
CreateStep1 step1=FillStep1();
CreateStep2 step2 = FillStep2();
CreateAllStep allStep = new CreateAllStep(step1, step2);
return View(allStep);
}
My controller is(when i click on the button, it's here where i would like send the model):
[HttpPost]
public ActionResult Create(String btn, CreateAllStep form)
{
if (Request.IsAjaxRequest())
{
if (btn != null)
{
if (btn == "Step1")
{
return PartialView("Step1",form.Step1);//not work
}
else if (btn == "Step2")
{
return PartialView("Step2");//work
}
else if(btn =="AllStep")
{
return PartialView("AllStep");
}
}
}
return View();
}
And my main view is :
#model SiteWebEmpty.Models.CreateAllStep
#{
ViewBag.Title = "Title";
}
<script type="text/javascript">
$(function () {
$('form').submit(function () {
$.post(this.action, $(this).serialize(), function (data) {
alert(data);
});
return false;
});
});
</script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<h2>Title</h2>
#using (Ajax.BeginForm("Create", //controller action name
"CreateStep", //controller name
new AjaxOptions //ajax options that tell mvc how to perform the replacement
{
UpdateTargetId = "ViewPage", //id of div to update
HttpMethod = "Post" //how to call the controller action
}, new { id = "FormName" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Create </legend>
<button type="submit" name="btn" value="Step1" id="Step1">Step 1</button>
<button type="submit" name="btn" value="Step2" id="Step2">Step 2</button>
<button type="submit" name="btn" value="AllStep" id="AllStep">All Step</button>
<div id="ViewPage">
#Html.Partial("Step1", Model)
</div>
</fieldset>
}
My partial view is:
#model SiteWebEmpty.Models.ArticleRequest.CreateArticle.ArticleRequestDisplayCreateAllStep
<fieldset>
<legend>Step 1</legend>
#Html.LabelFor(step1 => step1.Step1.Customer)
#Html.EditorFor(step1 => step1.Step1.Customer)
#Html.ValidationMessageFor(step1 => step1.Step1.Customer)
#Html.LabelFor(articleType => articleType.Step1.ArticleType)
#Html.DropDownList("ArticleType", Model.Step1.ArticleType)
#Html.ValidationMessageFor(articleType => articleType.Step1.ArticleType)
#Html.LabelFor(model => model.Step1.LabelType)
#Html.DropDownList("LabelType", Model.Step1.LabelType)
#Html.ValidationMessageFor(model => model.Step1.LabelType)
</fieldset>
render html:
<script src="/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
<h2>Title</h2>
<form action="/CreateStep/Create?Length=13" data-ajax="true" data-ajax-method="Post" data-ajax-mode="replace" data-ajax-update="#ViewPage" id="FormName" method="post"> <fieldset>
<legend>Create </legend>
<button type="submit" name="btn" value="Step1" id="Step1">Step 1</button>
<button type="submit" name="btn" value="Step2" id="Step2">Step 2</button>
<button type="submit" name="btn" value="AllStep" id="AllStep">All Step</button>
<div id="ViewPage">
<fieldset>
<legend>Step 1</legend>
<label for="Customer">Customer</label>
<input class="text-box single-line" data-val="true" data-val-required="Customer is required" id="Customer" name="Customer" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Customer" data-valmsg-replace="true"></span>
<label for="ArticleType">Article Type</label>
<select data-val="true" data-val-required="ArticleType is required" id="ArticleType" name="ArticleType"><option value="127">AR1 : New Product</option>
<option value="161">AR2 : Product Modification</option>
</select>
<span class="field-validation-valid" data-valmsg-for="ArticleType" data-valmsg-replace="true"></span>
<label for="LabelType">Label Type</label>
<select data-val="true" data-val-required="LabelType is required" id="LabelType" name="LabelType"><option value="129">Private Label</option>
</select>
<span class="field-validation-valid" data-valmsg-for="LabelType" data-valmsg-replace="true"></span>
</fieldset>
</div>
</fieldset>
</form>
Thanks for your help :) !
Could you post the final HTML?
I think that your #Html.Partial("Step1", Model.Step1) will render a input text with id like Customer or ArticleType instead of Step1.Customer and Step1.ArticleType. What will bind to CreateAllStep.Customer that doesn´t exist.
If you have the Headers sent by the browsers will help too.
Update: Change your partial Step1, to accept a CreateAllStep Model and try again
Try removing your constructor on your ViewModel:
public CreateAllStep(CreateStep1 step1, CreateStep2 step2)
{
this.Step1 = step1;
this.Step2 = step2;
}
And change the controller code to:
public ActionResult Create()
{
CreateAllStep allStep = new CreateAllStep{Step1 = FillStep1(), Step2 = FillStep2()};
return View(allStep);
}
I have run into issues with constructors with parameters when databinding.

Categories