This is how we implement cascade drop down for year and month. After selecting year/month the form is submitted. When the View back after Submit, the selected Year value is persist (as we have handling for this in Model), but the selected Month value is not persist. What need to do to persist the value?
Model
public class MyViewModel
{
public int? Year { get; set; }
public int? Month { get; set; }
public IEnumerable<SelectListItem> Years
{
get
{
return Enumerable.Range(2000, 12).Select(x => new SelectListItem
{
Value = x.ToString(),
Text = x.ToString()
});
}
}
}
Controller
The HttpGet and HttpPost action,
//
// GET: /MenuSix/
public ActionResult Index()
{
var model = new MyViewModel();
return View(model);
}
public ActionResult Months(int year)
{
if (year == 2011)
{
return Json(
Enumerable.Range(1, 3).Select(x => new { value = x, text = x }),
JsonRequestBehavior.AllowGet
);
}
return Json(
Enumerable.Range(1, 12).Select(x => new { value = x, text = x }),
JsonRequestBehavior.AllowGet
);
}
//
// POST: /MenuSix/
[HttpPost]
public ActionResult Index(MyViewModel myViewModel)
{
var month = myViewModel.Month; //11
var year = myViewModel.Year; //2011
return View(myViewModel);
}
View
What need to change here to persist month value "Enumerable.Empty()"?
#model DemoWeb.Models.MenuSix.MyViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.Year, new SelectList(Model.Years, "Value", "Text"), "-- select year --")
#Html.DropDownListFor(x => x.Month, Enumerable.Empty<SelectListItem>(), "-- select month --")
<div align="center">
<input type="submit" id="valSubmit" value="Save"/>
</div>
}
#section PageScriptsAndCSS{
<script type="text/javascript">
$(document).ready(function () {
$('#Year').change(function () {
debugger;
var selectedYear = $(this).val();
if (selectedYear != null && selectedYear != '') {
$.getJSON('#Url.Action("Months")', { year: selectedYear }, function (months) {
var monthsSelect = $('#Month');
monthsSelect.empty();
$.each(months, function (index, month) {
monthsSelect.append($('<option/>', {
value: month.value,
text: month.text
}));
});
});
}
});
});
</script>
}
Yes, you need to change the way you bind month's dropdown. As, you bind it with an empty list
You would not get the selected month value after form submit. I have changed your code in my way. let me know if it fits to your need.
Model
public class MyViewModel
{
public int? Year { get; set; }
public int? Month { get; set; }
public static IEnumerable<int> GetMonthsRangeOf(int year) {
return (year ==2011) ? Enumerable.Range(1, 3) : Enumerable.Range(1, 12);
}
public IEnumerable<SelectListItem> Years { get {
return Enumerable.Range(2000, 12).Select(x => new SelectListItem
{
Value = x.ToString(),
Text = x.ToString()
});
} }
public IEnumerable<SelectListItem> Months
{
get
{
IEnumerable<SelectListItem> months = null;
if (! this.Year.HasValue)
{
months = Enumerable.Empty<SelectListItem>();
}
else
{
months = GetMonthsRangeOf(this.Year.Value).Select(x => new SelectListItem
{
Value = x.ToString(),
Text = x.ToString()
});
}
return months;
}
}
}
Controller
public ActionResult Months(int year)
{
return Json(
MyViewModel.GetMonthsRangeOf(year).Select(x => new { value = x, text = x }),
JsonRequestBehavior.AllowGet
);
}
//
// POST: /MenuSix/
[HttpPost]
public ActionResult About(MyViewModel myViewModel)
{
var month = myViewModel.Month; //11
var year = myViewModel.Year; //2011
return View(myViewModel);
}
View
#model TestFreezeMVC.ViewModel.MyViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.Year, new SelectList(Model.Years, "Value", "Text"), "-- select year --")
#Html.DropDownListFor(x => x.Month, new SelectList(Model.Months, "Value", "Text"), "-- select month --");
<div align="center">
<input type="submit" id="valSubmit" value="Save"/>
</div>
}
<script type="text/javascript">
$(document).ready(function () {
$('#Year').change(function () {
var selectedYear = $(this).val();
if (selectedYear != null && selectedYear != '') {
$.getJSON('#Url.Action("Months")', { year: selectedYear }, function (months) {
var monthsSelect = $('#Month');
monthsSelect.empty();
$.each(months, function (index, month) {
monthsSelect.append($('<option/>', {
value: month.value,
text: month.text
}));
});
});
}
});
});
</script>
Suggest if I did something wrong..
Related
I get this error in my PartialView when I run my project "An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Unknown Module.
but was not handled in user code
Additional information: System.Web.Mvc.SelectListItem contains no definition for value"
I have two tables category and Product in my databse, using EntityFramework ADO.ENTITY and the project is ASP.NET MVC
In Product table I have ProductId, ProductName and CategoryId
I want to create Cascading from Category DropDownList to Product DropDownList , I mean I want first to chose Category and then all product with the same CategoryId.
But does not working as it is, and please Help me.
This is my Controller:
public class CasController : Controller
{
// GET: Cas
public ActionResult Index()
{
Db db = new Db();
ViewBag.Categories = new SelectList(GetCategoryList(), "CategoryId", "CategoryName");
return View();
}
public List<Category> GetCategoryList()
{
Db db = new Db();
List<Category> categories = db.Category.ToList();
return categories;
}
public ActionResult GetProductList(int catId)
{
using (Db db = new Db())
{
List<Product> prList = db.Product.Where(x => x.CatId == catId).ToList();
ViewBag.ProductOPtions = new SelectList(prList, "ProductId", "ProductName");
return PartialView("DisplayProduct");
}
}
}
And this is my Cascadingclass
public class CasCadingClass
{
public int CatId { get; set; }
public int PrId { get; set; }
}
This is Index view
#model Market.Models.CasCadingClass
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#if (ViewBag.Categories != null)
{
#Html.DropDownListFor(m => m.CatId, ViewBag.Categories as SelectList, "---Select Category---", new { #class = "form-control" })
}
#Html.DropDownListFor(m => m.PrId, new SelectList(""), "--Select Product--", new { #class = "form-control" })
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script>
$(document).ready(function () {
$("#CatId").change(function () {
var catId = $(this).val();
debugger
$.ajax({
type: "Post",
url: "/Cas/GetProductList?catId=" + catId,
contentType: "html",
success: function (response) {
debugger
$("#PrId").empty();
$("#PrId").append(response);
}
})
})
});
</script>
// Here in PartielView goes error
#model Market.Product
<option value="">--- select Product---</option>
#if (ViewBag.ProductOPtions != null)
{
foreach (var item in ViewBag.ProductOPtions)
{
<option value="#item.value">#item.Text</option>
}
}
Below is the code
[Route("users/{userid}/create")]
public ActionResult CreateSellerProfile(string userId)
{
var country = _locationService.GetCountries().ToDictionary(x => x.Id, x => x.CountryName);
var model = new SellerProfileViewModel { CountryDic = country };
model.UserId = userId;
return View(model);
}
[Authorize]
[HttpPost]
[Route("users/create")]
public ActionResult CreateSellerProfile(SellerProfileViewModel model)
{
if (!ModelState.IsValid)
{
model.StateDic = _locationService.Getstates(model.CountryId).ToDictionary(x => x.Id, x => x.StateName);
model.CountryDic = _locationService.GetCountries().ToDictionary(x => x.Id, x => x.CountryName);
return View(model);
}
var checkForalreadyExists = _userService.GetSellerProfileByUserId(model.UserId);
if (checkForalreadyExists == null)
{
var domainSellerObj = Mapper.Map<SellerProfileViewModel, SellerProfile>(model);
_userService.SaveSellerProfile(domainSellerObj);
return RedirectToAction("CreateSellerProfile", new { model.UserId });
}
else
{
SetMessage(MessageType.Danger, MessageConstant.GetMessage(Messages.SellerProfileAdded));
return RedirectToAction("CreateSellerProfile", new { model.UserId });
}
}
I want to ask that after we do POST to this action CreateSellerProfile,
then we want to redirect again to the same action CreateSellerProfile empty page,
we are facing the problem that it's not able to find the route that we defined i.e [Route("users/{userid}/create")]
http://pastebin.com/WU7XS3Vs
You need to specify the parameter name (userId) in the anonymous object:
return RedirectToAction("CreateSellerProfile", new { userId = model.UserId });
How is it possible that in a razor EditorTemplate the following commands generate a different value for the same ViewModel:
#Html.TextAreaFor(model => model.Value)
#Model.Value
And no, in the Value get property, the value is not changed
Update 1:
Sorry guys for the short message, you know, tired, frustrated...
Made a sample, got rid of all the partials and templates.
Give the textbox number 1, hit add, number 2, hit add, number 3, hit add.
The remove number 2.
The result is an out of sync between the textbox and the displayed value.
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
TestModel testModel = TestModel.Create();
Session["model"] = testModel;
return View("Index", testModel);
}
[HttpPost]
public ActionResult Submit(TestModel submitModel, string submit)
{
// merge values in current form
var testModel = Session["model"] as TestModel;
if (testModel == null) throw new Exception("No current model found.");
testModel.MergeFieldValues(submitModel);
if (submit.StartsWith("Add_"))
{
var rowGroupId = Guid.Parse(submit.Substring("Add_".Length));
TestRowGroup rowGroup = testModel.Groups.SelectMany(g => g.RowGroups).Single(rg => rg.RowGroupId == rowGroupId);
rowGroup.AddFieldRow();
}
if (submit.StartsWith("Del_"))
{
var fieldRowId = Guid.Parse(submit.Substring("Del_".Length));
testModel.RemoveFieldRow(fieldRowId);
}
return View("Index", testModel);
}
}
Model:
public class TestModel
{
public List<TestGroup> Groups { get; set; }
public static TestModel Create()
{
var testModel = new TestModel { Groups = new List<TestGroup>() };
var grp = new TestGroup { RowGroups = new List<TestRowGroup>() };
var rowGrp = new TestRowGroup { RowGroupId = Guid.NewGuid(), FieldRows = new List<TestFieldRow>() };
var fldRow = new TestFieldRow { FieldRowId = Guid.NewGuid(), Fields = new List<TestFormField>() };
var fld = new TestFormField { FieldId = Guid.NewGuid() };
fldRow.Fields.Add(fld);
rowGrp.FieldRows.Add(fldRow);
grp.RowGroups.Add(rowGrp);
testModel.Groups.Add(grp);
return testModel;
}
public void MergeFieldValues(TestModel src)
{
foreach (var srcField in src.Groups.SelectMany(g => g.RowGroups.SelectMany(rg => rg.FieldRows.SelectMany(fr => fr.Fields))))
{
var destField = Groups.SelectMany(g => g.RowGroups.SelectMany(rg => rg.FieldRows.SelectMany(fr => fr.Fields))).FirstOrDefault(f => f.FieldId == srcField.FieldId);
if (destField == null) throw new Exception("Field not found during merge");
destField.Value = srcField.Value;
}
}
public void RemoveFieldRow(Guid fieldRowId)
{
foreach (var group in Groups)
{
foreach (var rowGroup in group.RowGroups)
{
rowGroup.FieldRows.RemoveAll(fieldRow => fieldRow.FieldRowId == fieldRowId);
}
}
}
}
public class TestGroup
{
public List<TestRowGroup> RowGroups { get; set; }
}
public class TestRowGroup
{
public List<TestFieldRow> FieldRows { get; set; }
public Guid RowGroupId { get; set; }
public void AddFieldRow()
{
var newRow = new TestFieldRow
{
Fields = new List<TestFormField>()
};
newRow.FieldRowId = Guid.NewGuid();
var fld = new TestFormField { FieldId = Guid.NewGuid() };
newRow.Fields.Add(fld);
FieldRows.Add(newRow);
}
}
public class TestFieldRow
{
public Guid FieldRowId { get; set; }
public List<TestFormField> Fields { get; set; }
}
public class TestFormField
{
public Guid FieldId { get; set; }
public string Value { get; set; }
}
View:
#model FieldTest.Models.TestModel
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
#using (Html.BeginForm("Submit", "Home", FormMethod.Post))
{
for (int g = 0; g < Model.Groups.Count; g++)
{
for (int rg = 0; rg < Model.Groups[g].RowGroups.Count; rg++)
{
for (int fr = 0; fr < Model.Groups[g].RowGroups[rg].FieldRows.Count; fr++)
{
for (int f = 0; f < Model.Groups[g].RowGroups[rg].FieldRows[fr].Fields.Count; f++)
{
#Html.HiddenFor(model => model.Groups[g].RowGroups[rg].FieldRows[fr].Fields[f].FieldId)
#Model.Groups[g].RowGroups[rg].FieldRows[fr].Fields[f].Value
#Html.TextBoxFor(model => model.Groups[g].RowGroups[rg].FieldRows[fr].Fields[f].Value)
<button onclick="return confirm('Are you sure you would like to remove this row?');" type="submit" value="#string.Format("Del_{0}", Model.Groups[g].RowGroups[rg].FieldRows[fr].FieldRowId)" name="submit">Remove</button>
<hr />
}
}
<button type="submit" value="#string.Format("Add_{0}", Model.Groups[g].RowGroups[rg].RowGroupId)" name="submit">Add</button>
}
}
<input type="submit" value="Submit" name="submit" />
}
</body>
</html>
More importantly, are you sure this is an EditorTemplate problem? If you put the code in your main view, does it also happen? Did you try that? Or did you assume it was an EditorTemplate problem?
Since you neglected to provide any context for your question, all we can do is guess. More than likely, you have modified the contents of the view model in a post operation, and are now surprised that the Html helpers are using the old value rather than the value from the model.
If so, this is "by design", and a well documented (hundreds if not thousands of questions already here on SO about this issue). The MVC Helpers prefer the contents of the ModelState over the model itself in post operations. You have to clear the ModelState in order to work around it.
Below all my code,
*Model *
Below is Model code,
public class MyViewModel
{
public int? Year { get; set; }
public int? Month { get; set; }
public IEnumerable<SelectListItem> Years
{
get
{
return Enumerable.Range(2000, 12).Select(x => new SelectListItem
{
Value = x.ToString(),
Text = x.ToString()
});
}
}
}
Controller
Below is Controller code,
//
// GET: /MenuSix/
public ActionResult Index()
{
var model = new MyViewModel();
return View(model);
}
public ActionResult Months(int year)
{
if (year == 2011)
{
return Json(
Enumerable.Range(1, 3).Select(x => new { value = x, text = x }),
JsonRequestBehavior.AllowGet
);
}
return Json(
Enumerable.Range(1, 12).Select(x => new { value = x, text = x }),
JsonRequestBehavior.AllowGet
);
}
View
Below is View code,
#model DemoWeb.Models.MenuSix.MyViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(
x => x.Year,
new SelectList(Model.Years, "Value", "Text"),
"-- select year --"
)
#Html.DropDownListFor(
x => x.Month,
Enumerable.Empty<SelectListItem>(),
"-- select month --"
)
}
#section PageScriptsAndCSS{
<script type="text/javascript">
$('#Year').change(function () {
debugger;
var selectedYear = $(this).val();
if (selectedYear != null && selectedYear != '') {
$.getJSON('#Url.Action("Months")', { year: selectedYear },
function (months) {
var monthsSelect = $('#Month');
monthsSelect.empty();
$.each(months, function (index, month) {
monthsSelect.append($('<option/>', {
value: month.value,
text: month.text
}));
});
});
}
});
</script>
}
I'm testing above code, but in jquery code not called here, please suggest why the dropdown change event not called in jquery?
Wrap the javascript code in document.ready to ensure that control is available when binding then event. IT looks this javascript is rendered at the head and at that point drop down is not yet added to the DOM
$(document).ready(function()
{
$("#year").///rest of the code
});
I'm trying to initialize my checkbox in controller like the code below, but in the view it's not selected whether it's true or false
controller :
foreach (var item in AssignedUsers)
{
if (dc.App_UserTasks.Any(u => u.UserId == item.UserId && u.TaskId == ProjectTask.Id))
{
Users.Single(u => u.Id == item.Id).IsChecked = true;
}
else
{
Users.Single(u => u.Id == item.Id).IsChecked = false;
}
}
view:
#for (int i = 0; i < Model.Responsibles.Count; i++)
{
#Html.CheckBoxFor(u => u.Responsibles[i].IsChecked)
}
send model from controller to view :
var EPT = new EditProjectTaskModel
{
ProjectId = ProjectTask.ProjectId,
Title = ProjectTask.Title,
ProjectName = ProjectTask.App_Project.ProjectName,
Id = ProjectTask.Id,
Description = ProjectTask.Description,
EstimatedTime = ProjectTask.EstimatedTime,
Status = ProjectTask.Status,
Responsibles = Users.ToList()
};
return PartialView("_EditProjectTask", EPT);
Assuming your User ViewModel looks like this
public class UserViewModel
{
public string Name { set;get;}
public int UserId { set;get;}
public bool IsSelected { set;get;}
}
And you have your main view model has a collection of this UserViewModel
public class EditProjectTaskModel
{
public List<UserViewModel > Responsibles { set; get; }
public EditProjectTaskModel()
{
if(this.Responsibles ==null)
this.Responsibles =new List<UserViewModel >();
}
}
Create an editor template called Responsibles.cshtml with the below content
#model YourNameSpace.UserViewModel
#Html.CheckBoxFor(x => x.IsSelected)
#Html.LabelFor(x => x.IsSelected, Model.Name)
#Html.HiddenFor(x => x.UserId)
Now include that in your main view like this, instead of the loop
#model EditProjectTaskModel
#using (Html.BeginForm())
{
//other elements
#Html.EditorFor(m=>m.Responsibles)
<input type="submit" value="Save" />
}
If you want to get the selected checkboxes on a form submit.
[HttpPost]
public ActionResult Save(EditProjectTaskModel model)
{
List<int> userIDs=new List<int>();
foreach (UserViewModel user in model.Responsibles)
{
if (user.IsSelected)
{
//you can get the selected user id's here
userIDs.Add(user.UserId);
}
}
}