ASP.NET MVC - cascading drop down not being saved to database - asp.net-mvc

I created a 2-dependent cascading dropdown list:
Model Classes
COUNTRIES
public int COUNTRY_ID { get; set; }
public string COUNTRY_NAME { get; set; }
STATES
public int STATE_ID { get; set; }
public Nullable<int> COUNTRY_ID { internal get; set; }
public string STATE_NAME { get; set; }
CITIES
public int CITY_ID { get; set; }
public Nullable<int> STATE_ID { internal get; set; }
public Nullable<int> COUNTRY_ID { internal get; set; }
public string CITY_NAME { get; set; }
The drop-down list worked as expected. But when clicked on save button, nothing is saved.
Controller: CITIES
// Json Call to get state
public JsonResult GetStates(string id)
{
List<SelectListItem> states = new List<SelectListItem>();
var stateList = this.Getstate(Convert.ToInt32(id));
var stateData = stateList.Select(m => new SelectListItem()
{
Text = m.STATE_NAME,
Value = m.STATE_ID.ToString(),
});
return Json(stateData, JsonRequestBehavior.AllowGet);
}
// Get State from DB by country ID
public IList<STATES> Getstate(int CountryId)
{
return _statesService.GetStates().Where(stat => stat.COUNTRY_ID == CountryId).ToList();
}
//
public ActionResult Create()
{
ViewBag.COUNTRIES = new SelectList(_countriesService.GetCountries(), "COUNTRY_ID", "COUNTRY_NAME");
ViewBag.STATES = new SelectList(_statesService.GetStates(), "STATE_ID", "state_NAME");
return View();
}
[HttpPost]
public ActionResult Create(CITIES cities)
{
try
{
IEnumerable<COUNTRIES> lstCountries = _countriesService.GetCountries();
if (ModelState.IsValid)
{
cities.ACTION_STATUS = 0;
cities.CREATED_DATE = DateTime.Now;
_citiesService.AddCity(cities);
return RedirectToAction("Index");
}
}
catch
{
ModelState.AddModelError("", "We cannot add this Cities. Verify your data entries !");
}
ViewBag.COUNTRIES = new SelectList(_countriesService.GetCountries(), "COUNTRY_ID", "COUNTRY_NAME", cities.COUNTRY_ID);
ViewBag.STATES = new SelectList(_statesService.GetStates(), "STATE_ID", "STATE_NAME", cities.STATE_ID);
return View(cities);
}
View : Cities
<div class=" box box-body box-primary">
#*#using (Html.BeginForm())*#
#using (Html.BeginForm("Create", "Cities", FormMethod.Post, new { #class = "form-horizontal", #enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, null, new { #class = "text-danger" })
<div class="row .col">
<div style="margin-top:20px" class="mainbox col-md-12 col-md-offset-0 col-sm-8 col-sm-offset-2">
<div class="panel panel-info">
<div class="panel-heading">
<div class="panel-title">Create City</div>
</div>
<div class="panel-body">
<div class="col-md-4">
<div>
#Html.LabelFor(model => model.COUNTRY_ID, "Country Name", new { #class = "control-label" })
#Html.DropDownList("COUNTRIES", ViewBag.COUNTRIES as SelectList, "-- Please Select a Country --", new { style = "width:250px" })
#Html.ValidationMessageFor(model => model.COUNTRY_ID, null, new { #class = "text-danger" })
</div>
</div>
<div class="col-md-4">
<div>
#Html.LabelFor(model => model.STATE_ID, "State Name", new { #class = "control-label" })
#Html.DropDownList("STATES", new SelectList(string.Empty, "Value", "Text"), "-- Please select a State --", new { style = "width:250px", #class = "dropdown1" })
#Html.ValidationMessageFor(model => model.STATE_ID, null, new { #class = "text-danger" })
</div>
</div>
<div class="col-md-4">
<div>
#Html.LabelFor(model => model.CITY_NAME, "City Name", new { #class = "control-label" })
#Html.TextBoxFor(model => model.CITY_NAME, new { #style = "border-radius:3px;", #type = "text", #class = "form-control", #placeholder = Html.DisplayNameFor(m => m.CITY_NAME), #autocomplete = "on" })
#Html.ValidationMessageFor(model => model.CITY_NAME, null, new { #class = "text-danger" })
</div>
</div>
</div>
<div class="panel-footer">
<div class="panel-title">
<div class="form-actions no-color">
<input type="submit" value="Create" class="btn btn-success" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(document).ready(function () {
//Country Dropdown Selectedchange event
$("#COUNTRIES").change(function () {
$("#STATES").empty();
$.ajax({
type: 'POST',
url: '#Url.Action("GetStates")', // Calling json method
dataType: 'json',
data: { id: $("#COUNTRIES").val() },
// Get Selected Country ID.
success: function (states) {
$.each(states, function (i, state) {
$("#STATES").append('<option value="' + state.Value + '">' +
state.Text + '</option>');
});
},
error: function (ex) {
alert('Failed to retrieve states.' + ex);
}
});
return false;
})
});
</script>
When I clicked on Countries Drop-down list, it populates and the respective states are loaded as expected. When I clicked on Save button, nothing is being saved. Please what is the problem

Related

System.InvalidOperationException: 'The ViewData item that has the key 'X is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.'

I got this error when I want to Create my Contact. Need help I would be thankful.
My database SQL database table is connected via entity framework.
Home Controller / Create Action
[HttpGet]
public ActionResult Create()
{
List<Country> CountryList = db.Countries.ToList();
ViewBag.CountryList = new SelectList(CountryList, "CountryId", "CountryName");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CountryStateContactViewModel csvm)
{
if (!ModelState.IsValid)
{
return View(csvm);
}
Contact model = new Contact()
{
CountryId = csvm.CountryId,
StateId = csvm.StateId,
ContactId = csvm.ContactId,
ImeOsobe = csvm.ImeOsobe
...and all other fields
};
db.Contacts.Add(model);
try
{
db.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException db)
{
Exception raise = db;
foreach (var validationErrors in db.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
raise = new InvalidOperationException(message, raise);
}
}
throw raise;
}
return RedirectToAction("Index");
}
Now here is ViewModel
public int CountryId { get; set; }
[Required]
[Display(Name = "Naziv županije")]
public string CountryName { get; set; }
public int StateId { get; set; }
[Required]
[Display(Name = "Naziv općine")]
public string StateName { get; set; }
public int ContactId { get; set; }
public virtual Country Country { get; set; }
public virtual State State { get; set; }
....and all other fields
And finally here is "Create" view.
#model AkvizicijeApp_4_7.Models.CountryStateContactViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.CountryId, htmlAttributes: new { #class = "control-label col-md-2"
})
<div class="col-md-10">
#Html.DropDownListFor(model => model.CountryId, ViewBag.CountryList as SelectList, "--Select
Country--", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CountryId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.StateId, htmlAttributes: new { #class = "control-label col-md-2"
})
<div class="col-md-10">
#Html.DropDownListFor(model => model.StateId, new SelectList(" "), "--Select State--", new {
#class = "form-control" })
#Html.ValidationMessageFor(model => model.StateId, "", new { #class = "text-danger" })
</div>
</div>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>CountryStateContactViewModel</h4>
<hr />
<div class="form-group">
#Html.LabelFor(model => model.ContactId, htmlAttributes: new { #class = "control-label
col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ContactId, new { htmlAttributes = new { #class =
"form-control" } })
#Html.ValidationMessageFor(model => model.ContactId, "", new { #class = "text-danger"
})
</div>
</div>
And after that is all other fields and js for parent/child dropdown list.
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script>
$(document).ready(function () {
$("#CountryId").change(function () {
$.get("/Home/GetStateList", { CountryId: $("#CountryId").val() }, function (data) {
$("#StateId").empty();
$.each(data, function (index, row) {
$("#StateId").append("<option value='" + row.StateId + "'>" + row.StateName + "
</option>")
});
});
})
});
</script>
Please help me solve my problem. <3

MVC 5 dropdown value when selected

I have a category and sub category dropdown list in my view. I select the items in the DDL and submit. In my controller I can only see the categoryID, subCategoryID values for the DDL. I need to get the selected text values (categoryName, subCategoryName). In winforms it is known as the DisplayMember.
I can get the categoryName, subcategoryName values if I run a query based on the returned ID, but this feels like I'm hitting the database more times than I need to.
Here is my code:
ViewModel
public class MedicalCategoryVM
{
public int PersonID { get; set; }
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public int SubCategoryID { get; set; }
public string SubCategoryName { get; set; }
public string Notes { get; set; }
public Nullable<System.Guid> RowGuid { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public virtual Person Person { get; set; }
public List<MedicalCategory> MedicalCategories { get; set; }
}
View:
#model DofE.Models.MedicalCategoryVM
<br />
<br />
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="container">
#Html.Label("Medical Information", new { style = "font-size:16px; background-color:#002142; color:white;margin-left:10px" })
<div class="form-group">
#Html.DropDownListFor(model => model.CategoryID, new SelectList(Model.MedicalCategories,"CategoryID","CategoryName"),"--Select", new { #class = "form-control" })
</div>
<div class="form-group">
#Html.DropDownListFor(model => model.SubCategoryID, new SelectList(""), "--Select Sub Category", new { #class = "form-control" })
</div>
<div class="form-group">
<div class="row">
#Html.LabelFor(model => model.Notes, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Notes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Notes, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div class="row">
#Html.LabelFor(model => model.PersonID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PersonID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PersonID, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div style="padding-left:340px">
<span style="display: inline;">
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn btn-danger btn-sm" }) <input type="submit" value="Create" class="btn btn-primary btn-sm" />
</span>
</div>
#*<div class="test">
<div style="float: right;">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</div>*#
</div>
</div>
}
<script src="~/Scripts/jquery-3.4.1.min.js"></script>
<script>
$(document).ready(function () {
$("#CategoryID").change(function () {
$.get("/MedicalHistory/GetSubCategoryList", { CategoryID: $("#CategoryID").val() }, function (data) {
$("#SubCategoryID").empty();
$.each(data, function (index, row) {
$("#SubCategoryID").append("<option value='" + row.SubCategoryID + "'>" + row.SubCategoryName + "</option>")
});
});
})
});
</script>
Controller:
public ActionResult Create()
{
MedicalCategoryVM CategoryVM = new MedicalCategoryVM();
CategoryVM.MedicalCategories = db.MedicalCategories.ToList();
//ViewBag.CategoryList = new SelectList(CategoryList, "CategoryID", "CategoryName");
return View(CategoryVM);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "PersonID,CategoryName,SubCategoryName,Notes,RowGuid,ModifiedDate")] MedicalHistory medicalHistory, FormCollection form)
{
//string catName = form["CategoryName"].ToString();
//string subCatName = form["SubCategoryName"].ToString();
int catID = Convert.ToInt16(form["CategoryID"]);
int subCatID = Convert.ToInt16(form["SubCategoryID"]);
MedicalSubCategory cat = db.MedicalSubCategories.Find(subCatID);
medicalHistory.CategoryName = cat.CategoryName;
medicalHistory.SubCategoryName=cat.SubCategoryName;
medicalHistory.RowGuid = Guid.NewGuid();
medicalHistory.ModifiedDate = DateTime.Now;
if (ModelState.IsValid)
{
db.MedicalHistories.Add(medicalHistory);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(medicalHistory);
}

Only defualt values passed to database

I'm pretty new to programming and I'm strugling with quite simple "Create" controller and view.
In the view user is declaring values, which should be passed to database. Here's the model:
public class Expense
{
public int ExpenseID { get; set; }
[DisplayName("Data")]
[Column(TypeName = "DateTime2")]
public DateTime Date { get; set; }
[DisplayName("Wartość")]
public decimal Amount { get; set; }
[DisplayName("Opis")]
public string Details { get; set; }
[DisplayName("Rodzaj")]
public int CategoryID { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string Name { get; set; }
public virtual ICollection<Expense> Expenses { get; set; }
}
In the same view I want to include partial view for managing the categories (adding, removing).
To have this working I've implemented ViewModel:
public class ExpenseCreateViewModel
{
public Expense ExpenseCreate { get; set; }
public Category CategoryCreate { get; set; }
}
And here's the code for my View:
#model Wydatki2._0.Models.ExpenseCreateViewModel
#{
ViewBag.Title = "Create";
}
<h2>Dodaj wydatek</h2>
<table class="table">
<tr>
<th>
<div>
#using (Html.BeginForm("CreateExpense", "ExpenseCreate", FormMethod.Post, new { }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.ExpenseCreate.CategoryID, "Rodzaj", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CategoryID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.ExpenseCreate.CategoryID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ExpenseCreate.Amount, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ExpenseCreate.Amount, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ExpenseCreate.Amount, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ExpenseCreate.Date, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ExpenseCreate.Date, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ExpenseCreate.Date, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ExpenseCreate.Details, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ExpenseCreate.Details, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ExpenseCreate.Details, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Dodaj" class="btn btn-default" />
</div>
</div>
</div>
}
</div>
</th>
<th>
<div>
<input type="button" id="btn" class="btn btn-default" value="Dodaj/Usuń Kategorię" />
<p class="error">#ViewBag.Warning</p>
</div>
<div id="Create" style="display:none">
#Html.Partial("CreateCategory", Model.CategoryCreate)
</div>
</th>
</tr>
</table>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/toggle")
}
The problem is that when I submit the form only the CategoryID value is passed correctly. The rest of parameters have just default values. The partial view is working well - I'm able to add or remove categories, which then are passed to the main view.
The code for my Controller:
namespace Wydatki2._0.Controllers
{
public class ExpenseCreateController : Controller
{
private WydatkiContext db = new WydatkiContext();
public ActionResult Create(bool? warn = false)
{
ExpenseCreateViewModel model = new ExpenseCreateViewModel()
{
ExpenseCreate = new Expense(),
CategoryCreate = new Category()
};
var query = from b in db.Categories
where b.CategoryID != 1
select b;
if (warn.GetValueOrDefault())
{
ViewBag.Warning = "Nie możesz usunąć tej kategorii.";
}
ViewBag.CategoryID = new SelectList(query, "CategoryID", "Name");
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateExpense([Bind(Include = "ExpenseID,Date,Amount,Details,CategoryID")] Expense expense)
{
if (ModelState.IsValid)
{
db.Expenses.Add(expense);
db.SaveChanges();
return RedirectToAction("Create");
}
var query = from b in db.Categories
where b.CategoryID != 1
select b;
ViewBag.CategoryID = new SelectList(query, "CategoryID", "Name", expense.CategoryID);
return View(expense);
}
public ActionResult CreateCategory()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateCategory([Bind(Include = "CategoryID,Name")] Category category)
{
if (ModelState.IsValid)
{
Category cat = db.Categories.FirstOrDefault(c => c.Name== category.Name);
if (cat != null)
{
if (cat.CategoryID == 1 || cat.CategoryID ==2)
{
return RedirectToAction("Create", new { warn = true });
}
else
{
db.Categories.Remove(cat);
db.SaveChanges();
return RedirectToAction("Create");
}
}
else
{
db.Categories.Add(category);
db.SaveChanges();
return RedirectToAction("Create");
}
}
return View(category);
}
I'm inclined to believe that the problem is caused by the model, which I'm passing to the view, but I really don't know, how to pass it correctly... Anyone could help with this?
You should use
([Bind(Prefix="prefixhere")]Category category)
I assume your prefix should be CategoryCreate for category, which the extension from your model ExpenseCreateViewModel, same for your CreateExpense, your prefix should be ExpenseCreate, this way you tell your controller to expect your input names after this prefix, so it will look for CategoryID and Name in create category action after the prefix you passed.
Something Like this
([Bind(Prefix="CategoryCreate")]Category category)
([Bind(Prefix="ExpenseCreate")]Expense expense)

Model undefined when passing Model from View to Controller using AJAX

When I tried to used debugger; in ajax to check if I'm able to serialize the form it say it is "undefined". I don't encounter an error but The value i input in the view does not pass to the controller. This is my reference https://stick2basic.wordpress.com/2013/04/14/how-to-pass-model-from-view-to-controller-using-jquery/
VIEW
<script type="text/javascript">
$(document).ready(function () {
$('#btnsubmit').click(function (e) {
e.preventDefault();
if ($("#OrderForm").valid()) { //if you use validation
$.ajax({
url: $("#OrderForm").attr('action'),
type: $("#OrderForm").attr('method'),
data: $("#OrderForm").serialize(),
success: function (data) {
alert("success");
}
});
}
});
});
</script>
#using (Html.BeginForm("_Order", "Account", FormMethod.Post, new { id = "OrderForm" }))
{
<div class="form-group">
<div class="col-md-3">
#Html.LabelFor(model => model.MerchantEmail, htmlAttributes: new { #class = "control-label col-md-2" })
</div>
<div class="col-md-9">
#Html.TextBoxFor(model => model.MerchantEmail, new { #Value = "abc#gmail.com",#class = "form-control" })
#Html.ValidationMessageFor(model => model.MerchantEmail, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" value="Create" id="btnsubmit" class="btn btn-primary" />
</div>
</div>
}
Controller
[AllowAnonymous]
[HttpPost]
public ActionResult _Order(OrderModel model)
{
List<OrderModel> orderlist = new List<OrderModel>();
if (Session["OrderList"] != null)
{
orderlist = Session["OrderList"] as List<OrderModel>;
orderlist.Add(model);
}
Session["OrderList"] = orderlist;
return PartialView();
}
MODEL
public class OrderModel
{
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[StringLength(35)]
public string FirstName { get; set; }
[StringLength(35)]
public string MiddleName { get; set; }
[StringLength(35)]
public string LastName { get; set; }
[StringLength(255)]
public string Address { get; set; }
[StringLength(40)]
public string Province { get; set; }
[StringLength(40)]
public string Town { get; set; }
[StringLength(13)]
public string MobileNo { get; set; }
[Required(ErrorMessage = "Please fill up Merchant Email.")]
[DataType(DataType.EmailAddress)]
public string MerchantEmail { get; set; }
[Required(ErrorMessage = "Please enter the exact amount.")]
[DataType(DataType.Currency)]
public float OrderAmount { get; set; }
public string OrderSkuCode { get; set; }
[Required(ErrorMessage = "Please fill up order details.")]
[StringLength(5000)]
public string OrderDetails { get; set; }
}
There are two things you are doing at the same time, you can have ajax or post the data directly to the controller.
#using (Html.BeginForm("_Order", "Account", FormMethod.Post, new { id = "OrderForm" }))
{
<div class="form-group">
<div class="col-md-3">
#Html.LabelFor(model => model.MerchantEmail, htmlAttributes: new { #class = "control-label col-md-2" })
</div>
<div class="col-md-9">
#Html.TextBoxFor(model => model.MerchantEmail, new { #Value = "abc#gmail.com",#class = "form-control" })
#Html.ValidationMessageFor(model => model.MerchantEmail, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" value="Create" id="btnsubmit" class="btn btn-primary" />
</div>
</div>
}
Here you are posting the data directly to the controller (Ajax is for Asynchronous Transfer) , this will by pass the Ajax request in the script.
If you want to post it through Ajax here is the code changes you need to do
<form id="form1">
<div class="form-group">
<div class="col-md-3">
#Html.LabelFor(model => model.MerchantEmail, htmlAttributes: new { #class = "control-label col-md-2" })
</div>
<div class="col-md-9">
#Html.TextBoxFor(model => model.MerchantEmail, new { #Value = "abc#gmail.com",#class = "form-control" })
#Html.ValidationMessageFor(model => model.MerchantEmail, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" value="Create" id="btnsubmit" class="btn btn-primary" />
</div>
</div>
</form>
<script type="text/javascript">
$(document).ready(function () {
$('#btnsubmit').click(function (e) {
e.preventDefault();
var data = new FormData($("#form1")[0]);
if ($("#OrderForm").valid()) { //if you use validation
$.ajax({
url: '#Url.Action("_Order","Your Controller Name")',
dataType: "json",
data: data,
success: function (data) {
alert("success");
}
});
}
});
});
</script>

MVC dropdown update the form not working

I know there are other posts for this, but I'm still not wrapping my head around it.
I would like write my MVC view to use a ViewModel that will allow text fields to change based on selections in a dropdownlist?
In the below example, I have a collection of Templates. I would like to see the dropdown list the Templates, then the user would select an item from the DropDownList, the code would populate the text fields, the user could edit those text fields, and finally submit the form with their changes.
What happens now is that every time the Submit code is called, it acts as if the dropdown was selected.
Model and ViewModel:
public class Template
{
[Display(Name = "Template")]
public int TemplateId {get; set;}
public string TemplateName {get; set;}
public string Subject {get; set;}
public string Message {get; set;}
}
public class TemplateViewModel
{
[Display(Name = "Template")]
public int LetterTemplateId {get; set;}
public ICollection<Template> Templates { get; set; }
}
View:
#model MyWebProject.ViewModels.TemplateViewModel
#using (Html.BeginForm("callforcontentproposaldetail","Project", FormMethod.Post, new {id = "frmProposalDetail"}))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Email Template</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.LetterTemplateId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-4">
#Html.DropDownListFor(m => m.LetterTemplateId,
new SelectList(Model.Templates as IEnumerable, "TemplateId", "TemplateName"),
new { #class = "form-control", onchange = "document.getElementById('frmProposalDetail').submit();", id = "ddlTemplate" })
#Html.ValidationMessageFor(model => model.LetterTemplateId, "", new { #class = "text-danger" })
</div>
</div>
<div id="letterTemplateEditArea">
<div class="form-group col-md-12">
<div class="row">
#Html.TextBoxFor(model => model.SelectedTemplate.TemplateSubject, new { #class = "form-control" })
#Html.LabelFor(model => model.SelectedTemplate.Message, new { #class = "control-label" })
#Html.TextAreaFor(model => model.SelectedTemplate.Message, new { #class = "form-control", #style = "max-width:100%;height:400px;font-size:11px;" })
</div>
</div>
<br />
</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>
</div>
}
Controller Code:
public ActionResult callforcontentproposaldetail(Guid id)
{
var proposal = db.CallForContentProposal.Find(id);
var model = Mapper.Map<CallForContentProposalViewModel>(proposal);
if (TempData["LetterTemplateId"] != null)
{
var emailTempId = 0;
if (int.TryParse((string)TempData["LetterTemplateId"], out emailTempId))
{
var template = model.Templates.FirstOrDefault(t => t.TemplateId == emailTempId);
model.SelectedTemplateId = emailTempId;
model.Subject = template.Subject;
model.Message = template.Body;
}
}
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult callforcontentproposaldetail(CallForContentProposalViewModel model, string SelectedTemplateId = "")
{
// Do some saving of the current data
// ...
db.SaveChanges();
// If this is the dropdownlist calling, redirect back to display the text fields populated
if (!string.IsNullOrEmpty(SelectedTemplateId))
{
TempData["LetterTemplateId"] = SelectedTemplateId;
return RedirectToAction("callforcontentproposaldetail", new { id = model.CallForContentProposalId });
}
// On Submit, do other tasks
return RedirectToAction("callforcontent", new {id = model.CallForContentId});
}
I figured it out. Thanks to your comments, I worked out a way to use Ajax to do this for our situation (I tried to make it as generic as possible to reuse elsewhere):
View:
<div class="form-group">
#Html.LabelFor(model => model.LetterTemplateId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-4">
#Html.DropDownListFor(m => m.LetterTemplateId,
Model.EmailTemplateSelect(),
new { #class = "form-control", onchange = "EmailTemplateLoad.call(this,this.options[this.selectedIndex].value,'LetterTemplateSubject','LetterTemplateBody');", id = "ddlReviewRole" })
#Html.ValidationMessageFor(model => model.LetterTemplateId, "", new { #class = "text-danger" })
</div>
</div>
Javascript:
EmailTemplateLoad = function(id, subjectTbName, messageTbName) {
debugger;
var ServiceUrl = "/Project/LoadTemplate?id=" + id;
var content = '';
$.support.cors = true;
$.ajax({
type: 'GET',
url: ServiceUrl,
async: true,
cache: false,
crossDomain: true,
contentType: "application/json; charset=utf-8",
dataType: 'json',
error: function (xhr, err) {
},
success: function (result, status) {
$('#' + subjectTbName).val(result[0].Subject);
$('#' + messageTbName).val(result[0].Message);
}
});
};
Controller:
public ActionResult LoadTemplate(int id)
{
var result = (from t in db.EmailBodyTemplate
where t.EmailTemplateId == id
select new
{
t.Subject,
Message = t.Body
});
return Json(result, JsonRequestBehavior.AllowGet);
}
I also followed this example, although it was incomplete:
CodeProject example

Resources