How to get items in cascade selectList after posting in ASP Core MVC - asp.net-mvc

I have a cascade list for Country/Province/City and it works fine in the create and edit action except for one thing, it always becomes empty in the edit get, here is my code:
public class LocationController : Controller
{
public List<Country> countries = new List<Country>
{
new Country(){Id=1,Name="Country1"},
new Country(){Id=2,Name="Country2"}
};
public List<Province> provinces = new List<Province>()
{
new Province() { Id = 1,CountryId = 1,Name = "Province1"},
new Province() { Id = 2,CountryId = 2,Name = "Province2"},
};
public List<City> cities = new List<City>()
{
new City() { Id = 1,ProvinceId = 1,Name = "City1" },
new City() { Id = 2,ProvinceId = 2,Name = "City2" },
new City() { Id = 3,ProvinceId = 2,Name = "City3" },
};
public IActionResult Province(int value)
{
var l = provinces.Where(x => x.CountryId == value).ToList();
return Json(l);
}
public IActionResult City(int value)
{
var c = cities.Where(c => c.ProvinceId == value).ToList();
return Json(c);
}
}
the Edit view:
<div class="form-group row">
<div class="col-2">
<label asp-for="Country" class="col-form-label"></label>
</div>
<div class="col-sm-5">
<select id="CountryList" asp-for="Country" asp-items="#new LocationController().countries.Select(c=> new SelectListItem() {Text=c.Name,Value=c.Id.ToString() }).ToList() as IEnumerable<SelectListItem>" class="form-control">
<option selected disabled value="">--- Choose ---</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Province" class="col-form-label"></label>
</div>
<div class="col-sm-5">
<select id="ProvinceList" asp-for="Province" data-url="#Url.Action("Province","Location")" class="form-control">
<option selected disabled value="">--- Choose ---</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="City" class="col-form-label"></label>
</div>
<div class="col-sm-5">
<select id="CityList" asp-for="City" data-url="#Url.Action("City","Location")" class="form-control">
<option selected disabled value="">--- Choose ---</option>
</select>
</div>
</div>
This is the Javascript:
#section Scripts {
<script>
$(function () {
$("#CountryList").change(function () {
$("#CityList").empty();
var v = $(this).val();
var url = $("#ProvinceList").data("url") + '?value=' + v;
$.getJSON(url, function (data) {
$("#ProvinceList").empty();
$("#ProvinceList").append('<option selected disabled value="">--- Choose ---</option>');
$.each(data, function (i, item) {
$("#ProvinceList")
.append($("<option>").text(item.name).val(item.id));
});
});
});
$("#ProvinceList").change(function () {
var v = $(this).val();
var url = $("#CityList").data("url") + '?value=' + v;
$.getJSON(url, function (data) {
$("#CityList").empty();
$("#CityList").append('<option selected disabled value="">--- Choose ---</option>');
$.each(data, function (i, item) {
$("#CityList")
.append($("<option>").text(item.name).val(item.id));
});
});
});
});
$('#formId').submit(function () {
$('#CountryList option').val(function () {
return $(this).text();
});
$('#ProvinceList option').val(function () {
return $(this).text();
});
$('#CityList option').val(function () {
return $(this).text();
});
});
</script>
}
and of course in the get action I tried to get the user's location from the database, and its working in the get:
[HttpGet]
public async Task<IActionResult> Edit(string id)
{
var user = await _userManager.FindByIdAsync(id);
EditUserViewModel modelVM = new EditUserViewModel
{
Country = user.Country,
Region = user.Region,
City = user.City,
};
return View(modelVM);
}
but in the view the province/region and city are empty:
If I click update province and city will be null.

Here is a working demo about how to pass the selected item to the action:
Model:
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Province
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public int ProvinceId { get; set; }
}
Update:
It seems you want to edit one user and the edit view would display the user's default city,province and country.So I think your js is no need in edit view.
Here is a working demo like below:
Model:
public class UserProfile
{
public string Id { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Province { get; set; }
}
public class EditUserViewModel
{
public string City { get; set; }
public string Country { get; set; }
public string Province { get; set; }
}
Index.cshtml(display the user data):
#model IEnumerable<UserProfile>
<table>
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Country)
</th>
<th>
#Html.DisplayNameFor(model => model.Province)
</th>
<th>
#Html.DisplayNameFor(model => model.City)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Country)
</td>
<td>
#Html.DisplayFor(modelItem => item.Province)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.Id">Edit</a>
</td>
</tr>
}
</tbody>
</table>
Edit.cshtml:
#model EditUserViewModel
<form id="formId" asp-controller="Location" asp-action="Edit">
<div class="form-group row">
<div class="col-2">
<label asp-for="Country" class="col-form-label"></label>
</div>
<div class="col-sm-5">
//change here....
<select id="CountryList" asp-for="Country" asp-items="#ViewBag.Country" class="form-control">
<option selected disabled value="">--- Choose ---</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Province" class="col-form-label"></label>
</div>
<div class="col-sm-5">
//change here....
<select id="ProvinceList" asp-for="Province" asp-items="#ViewBag.Province" data-url="#Url.Action("Province","Location")" class="form-control">
<option selected disabled value="">--- Choose ---</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="City" class="col-form-label"></label>
</div>
<div class="col-sm-5">
//change here....
<select id="CityList" asp-for="City" asp-items="#ViewBag.City" data-url="#Url.Action("City","Location")" class="form-control">
<option selected disabled value="">--- Choose ---</option>
</select>
</div>
</div>
<input type="submit" value="aaa" />
</form>
#section Scripts
{
<script>
$(function () {
$("#CountryList").change(function () {
$("#CityList").empty();
var v = $(this).val();
var url = $("#ProvinceList").data("url") + '?value=' + v;
$.getJSON(url, function (data) {
$("#ProvinceList").empty();
$("#ProvinceList").append('<option selected disabled value="">--- اختر ---</option>');
$.each(data, function (i, item) {
$("#ProvinceList")
.append($("<option>").text(item.name).val(item.id));
});
});
});
$("#ProvinceList").change(function () {
var v = $(this).val();
var url = $("#CityList").data("url") + '?value=' + v;
$.getJSON(url, function (data) {
$("#CityList").empty();
$("#CityList").append('<option selected disabled value="">--- اختر ---</option>');
$.each(data, function (i, item) {
$("#CityList")
.append($("<option>").text(item.name).val(item.id));
});
});
});
});
$('#formId').submit(function () {
$('#CountryList option').val(function () {
return $(this).text();
});
$('#ProvinceList option').val(function () {
return $(this).text();
});
$('#CityList option').val(function () {
return $(this).text();
});
});
</script>
}
HomeController:
public class HomeController : Controller
{
private List<UserProfile> users = new List<UserProfile>()
{
new UserProfile(){Id="1",Province="1",Country="1",City="1"},
new UserProfile(){Id="2",Province="2",Country="2",City="3"},
};
public IActionResult Index()
{
return View(users);
}
[HttpGet]
public async Task<IActionResult> Edit(string id)
{
var user = users.Where(a => a.Id == id).FirstOrDefault();
ViewBag.Province = new SelectList(new LocationController().provinces,"Id","Name", user.Province);
ViewBag.City = new SelectList(new LocationController().cities,"Id","Name", user.City);
ViewBag.Country = new SelectList(new LocationController().countries,"Id","Name", user.Country);
EditUserViewModel modelVM = new EditUserViewModel
{
Country = user.Country,
Province = user.Province,
City = user.City,
};
return View(modelVM);
}
[HttpPost]
public IActionResult Edit(string city, string province, string country)
{
return RedirectToAction("Index");
}
}
Result:

Related

How can i save changes made to the database

I have the following action for Edit,
In the view i have the following code
<form asp-action="Edit" class="form-horizontal">
<input type="text" asp-for="Code" value="#Model.Code" class="form-control" />
<button class="btn btn-success Product-edit-button" role="button">Save</button>
</form>
How can i save changes to Database on button click?
Here is what i tried, edit model look like
public async Task<IActionResult> editModel(int? id)
{
if (id == null)
{
return NotFound();
}
var ProductList = (await ProductService.GetProducts()).ToList();
var Product = ProductList.FirstOrDefault(a => a.ID == id);
if (Product == null)
{
return NotFound();
}
return View(Product);
}
Edit Action looks like as follow
public async Task<IActionResult> Edit(ProductEditModel editModel)
{
if (id == null)
{
return NotFound();
}
var ProductList = (await ProductService.GetProducts()).ToList();
var Product = ProductList.FirstOrDefault(a => a.ID == id);
if (Product == null)
{
return NotFound();
}
Product.Code = editModel.Code;
ProductService.EditProduct(Product);
return View(Product);
}
You need another action that accept POST request and send edited data to it.
public async Task<IActionResult> Edit(ProductEditModel editModel)
{
if (id == null)
{
return NotFound();
}
var ProductList = (await ProductService.GetProducts()).ToList();
var Product = ProductList.FirstOrDefault(a => a.ID ==editModel.Id);
if (Product == null)
{
return NotFound();
}
Product.Code=editModel.Code;
ProductService.EditProduct(Product);
return View(Product);
}
The Model :
public class ProductEditModel {
public int Id {get;set;}
public string code{get; set;}
}
The View:
<form asp-action="Edit" class="form-horizontal">
<input type="hidden" asp-for="Id" value="#Model.Id" class="form-control" />
<input type="text" asp-for="Code" value="#Model.Code" class="form-control" />
<button class="btn btn-success Product-edit-button" role="button">Save</button>
</form>
Here is a working demo like below:
1.Model:
public class ProductEditModel
{
public int ID { get; set; }
public string Code { get; set; }
}
2.View(Edit.cshtml):
#model ProductEditModel
<h4>ProductEditModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="ID" />
<div class="form-group">
<label asp-for="Code" class="control-label"></label>
<input asp-for="Code" class="form-control" />
<span asp-validation-for="Code" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
3.Controller:
public class ProductEditModelsController : Controller
{
private readonly YourContext _context;
public ProductEditModelsController(YourContext context)
{
_context = context;
}
// GET: ProductEditModels/Edit/5
//display edit view
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var productEditModel = await _context.ProductEditModel.FindAsync(id);
if (productEditModel == null)
{
return NotFound();
}
return View(productEditModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(ProductEditModel productEditModel)
{
if (ModelState.IsValid)
{
_context.Update(productEditModel);//update model
await _context.SaveChangesAsync();//save to database
return RedirectToAction(nameof(Index));
}
return View(productEditModel);
}
}
4.DbContext:
public class YourContext: DbContext
{
public YourContext(DbContextOptions<YourContext> options)
: base(options)
{
}
public DbSet<ProductEditModel> ProductEditModel { get; set; }
}
5.Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<YourContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("YourConnnection"))); //connect to sql server
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//...
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Privacy}/{id?}");
});
}
Result:
Update:
1.Index.cshtml:
#model IEnumerable<ProductEditModel>
#{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Code)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Code)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="#item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="#item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
2.Index action in controller:
public async Task<IActionResult> Index()
{
return View(await _context.ProductEditModel.ToListAsync());
}
If you do not understand successfully,please learn the mvc tutorial below first.
Reference:
https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/adding-model?view=aspnetcore-3.1&tabs=visual-studio

POSTing KnockoutJS model to MVC controller, List<T> in List<T> is empty

I have little experience with KnockoutJS so please bear with me.
I have a basic example that I want to get working so I can expand it to my project.
For this example you click the button and the AddSku method is called to return QuoteLine data with List.
However, as the diagram shows, BomDetails is empty:
Models:
public class QuoteViewModel
{
public int Id { get; set; }
public string QuoteName { get; set; }
public IList<QuoteLine> QuoteLines { get; set; }
}
public class QuoteLine
{
public string Description { get; set; }
public string Sku { get; set; }
public IList<BomDetail> BomDetails = new List<BomDetail>();
}
public class BomDetail
{
public string Name { get; set; }
}
Controller methods:
[HttpGet]
public ActionResult CreateQuote()
{
QuoteViewModel quote = new QuoteViewModel();
quote.Id = 10;
quote.QuoteName = "Test Create Quote";
quote.QuoteLines = new List<QuoteLine>();
return View(quote);
}
[HttpPost]
public ActionResult CreateQuote(QuoteViewModel viewModel)
{
if (ModelState.IsValid)
{
}
return RedirectToAction("CreateQuote");
}
[HttpGet]
public JsonResult AddSku()
{
QuoteLine line = new QuoteLine();
line.BomDetails = new List<BomDetail>();
line.Sku = "TestSku";
line.Description = "TestDescription";
line.BomDetails.Add(new BomDetail
{
Name = "BOM Detail 1"
});
line.BomDetails.Add(new BomDetail
{
Name = "BOM Detail 2",
});
return Json(line, JsonRequestBehavior.AllowGet);
}
The view:
#model EngineeringAssistantMVC.ViewModels.QuoteViewModel
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<div class="container-fluid">
<h2>Create Quote</h2>
#using (Html.BeginForm("CreateQuote", "Test", FormMethod.Post, new { #id = "createQuoteForm", #class = "form-horizontal", role = Model, enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.QuoteName)
<h3>Quote Lines</h3>
<table class="table master-detail-table" id="receiving-table">
<thead>
<tr>
<th>SKU</th>
<th>Description</th>
</tr>
</thead>
<tbody data-bind="foreach: QuoteLines">
<tr>
<td>
<input class='form-control' data-bind='value: $data.Sku, attr: { name: "QuoteLines[" + $index() + "].Sku" } ' type='text' readonly='readonly' />
</td>
<td>
<input class='form-control' data-bind='value: $data.Description, attr: { name: "QuoteLines[" + $index() + "].Description" } ' type='text' readonly='readonly' />
</td>
</tr>
<tr class="detail-row">
<td colspan="7">
<table class="table">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody data-bind="foreach: BomDetails">
<tr>
<td>
<input class='form-control' data-bind='value: $data.Name, attr: { name: "BomDetails[" + $index() + "].Name" } ' type='text' readonly='readonly' />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<h3>Add Sku from Db</h3>
<div class="row">
<div class="col-sm-2">
<input type="button" value="Add Sku" id="btnAddSku" class="btn btn-satcom-primary btn-wider" />
</div>
</div>
<h3>Submit</h3>
<div class="row">
<div class="col-sm-1">
<input type="submit" value="Submit" class="btn btn-satcom-primary btn-wider" id="btnSubmit" />
</div>
</div>
}
</div>
<script type="text/javascript">
$(function () {
quoteViewModel = new QuoteViewModel();
ko.applyBindings(quoteViewModel);
$('#btnAddSku').off().on('click', function () {
AddFromDb();
});
});
function QuoteViewModel() {
var self = this;
self.Id = ko.observable('#Model.Id');
self.QuoteName = ko.observable('#Model.QuoteName');
self.QuoteLines = ko.observableArray([]);
self.AddQuoteLine = function (sku, description, bomDetails) {
self.QuoteLines.push(new QuoteLineViewModel(sku, description, bomDetails));
}
}
function QuoteLineViewModel(sku, description, bomDetails) {
var self = this;
self.Sku = sku;
self.Description = description;
self.BomDetails = ko.observableArray([]);
$.each(bomDetails, function (index, item) {
self.BomDetails.push(new BomDetailViewModel(item.Name));
});
}
function BomDetailViewModel(name) {
var self = this;
self.Name = name;
}
function AddFromDb() {
$.ajax({
type: "GET",
url: '#Url.Action("AddSku", "Test")',
success: function (line) {
window.quoteViewModel.AddQuoteLine(line.Sku, line.Description, line.BomDetails);
}
});
}
I have tried so many things to get it populated but can't figure out where the problem lies, but I hope it is just something silly that I'm doing or not doing.
I have also tried using ko.mapping but I can't get that working either.
I managed to get this working so hopefully it will help somebody else in the future.
I removed the #Using (Html.BeginForm)
I changed the submit button to a normal button and added data-bind to a fucntion
<input type="button" value="Submit" class="btn btn-satcom-primary btn-wider" id="btnSubmit" data-bind="click:SaveToDatabase" />
The SaveToDatabase function:
self.SaveToDatabase = function () {
var dataToSend = ko.mapping.toJSON(self);
$.ajax({
type: "POST",
url: '#Url.Action("CreateQuote", "Test")',
contentType: 'application/json',
data: dataToSend,
success: function (data) {
},
error: function (err) {
console.log(err.responseText);
}
});
}
This correctly sends all the data to the controller.

ASP.Net MVC Custom client side validation not firing

i have the below jquery unobtrusive code which is not firing.
$.validator.unobtrusive.adapters.add('customvalidation', ['productname'], function (options) {
options.rules['customvalidation'] = { productname: options.params.productname };
});
$.validator.addMethod("customvalidation", function (value, element, param) {
alert(param.productname);
return false;
});
but the above code suppose to show alert i guess when pressing button to submit my form.
here is my full code
Model and view model
public class Product
{
public int ID { set; get; }
public string Name { set; get; }
}
public class Hobby
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class SampleViewModel
{
[Display(Name = "Products")]
public List<Product> Products { set; get; }
//[AtleastOne(ErrorMessage = "Select at least one checkbox.")]
public List<Hobby> Hobbies { get; set; }
[Required(ErrorMessage = "Select any Product")]
public int SelectedProductId { set; get; }
[Required(ErrorMessage = "Select Male or Female")]
public string Gender { get; set; }
public bool? IsAdult { get; set; }
public int? Age { get; set; }
[ConditionalAttribute(SelectedProductID = "SelectedProductId", Products = "Products", Hobbies = "Hobbies",IsAdult="IsAdult",Age="Age")]
public string ErrorMsg { get; set; }
}
Custom server side validation
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class ConditionalAttribute : ValidationAttribute , IClientValidatable
{
public string SelectedProductID = "", Products = "", Hobbies="";
public string IsAdult = "";
public string Age ="";
string _productname = "";
bool _hashobby = false;
bool _isadult = false;
int _age = 0;
public ConditionalAttribute() { }
public ConditionalAttribute(string SelectedProductId, string Products, string Hobbies, string IsAdult, string Age)
{
this.SelectedProductID = SelectedProductId;
this.Products = Products;
this.Hobbies = Hobbies;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
//getting selected product
Product oProduct = null;
ValidationResult validationResult = ValidationResult.Success;
var containerType = validationContext.ObjectInstance.GetType();
var SelectedProductID = containerType.GetProperty(this.SelectedProductID);
Int32 selectedproduct = (Int32)SelectedProductID.GetValue(validationContext.ObjectInstance, null);
var ProductList = containerType.GetProperty(this.Products);
List<Product> oProducts = (List<Product>)ProductList.GetValue(validationContext.ObjectInstance, null);
oProduct = oProducts.Where(e => e.ID == selectedproduct).FirstOrDefault();
_productname = oProduct.Name;
if (_productname != "iPod")
{
var field2 = containerType.GetProperty(this.Hobbies);
List<Hobby> hobbies = (List<Hobby>)field2.GetValue(validationContext.ObjectInstance, null);
foreach (var hobby in hobbies)
{
if (hobby.IsSelected)
{
_hashobby = true;
break;
}
//return ValidationResult.Success;
}
if (!_hashobby)
{
this.ErrorMessage = "Select Any Hobbie's checkbox";
return new ValidationResult(ErrorMessage);
//return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
var PropIsAdult = containerType.GetProperty(this.IsAdult);
if (PropIsAdult.GetValue(validationContext.ObjectInstance, null) != null)
{
_isadult = (bool)PropIsAdult.GetValue(validationContext.ObjectInstance, null);
if (_isadult)
{
var PropAge = containerType.GetProperty(this.Age);
if (PropAge.GetValue(validationContext.ObjectInstance, null) != null)
{
_age = (Int32)PropAge.GetValue(validationContext.ObjectInstance, null);
if (_age != null && _age <= 0)
{
this.ErrorMessage = "Age is compulsory for adult";
return new ValidationResult(ErrorMessage);
}
}
else
{
this.ErrorMessage = "Age is compulsory for adult";
return new ValidationResult(ErrorMessage);
}
}
}
return ValidationResult.Success;
}
// Implement IClientValidatable for client side Validation
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "customvalidation",
};
rule.ValidationParameters.Add("productname", _productname);
yield return rule;
}
}
My view code
#model AuthTest.Models.SampleViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm("Index", "TestVal", FormMethod.Post, new { name = "TestVal" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>DateValTest</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Products, htmlAttributes: new { #class = "control-label col-md-2", style = "padding-top:0px;" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedProductId, new SelectList(Model.Products, "ID", "Name"), "-- Select Product--")
#Html.ValidationMessageFor(model => model.SelectedProductId, "", new { #class = "text-danger" })
#for (int i = 0; i < Model.Products.Count(); i++)
{
<div>
#Html.HiddenFor(model => Model.Products[i].Name)
#Html.HiddenFor(model => Model.Products[i].ID)
</div>
}
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<b>Gender</b><br />
<label>
<span>Male</span> #Html.RadioButtonFor(model => model.Gender, "Male", new { style = "width:20px;" })
<span>Female</span>#Html.RadioButtonFor(model => model.Gender, "Female", new { style = "width:20px;" })
</label>
<label>
</label>
#Html.ValidationMessageFor(model => model.Gender, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10 input-validation-error">
<b>Hobbies</b><br />
#for (int x = 0; x < Model.Hobbies.Count(); x++)
{
#Html.CheckBoxFor(p => p.Hobbies[x].IsSelected, new { #class = "hobbycls", id = "Hobbies" }) #:
#Html.LabelFor(p => p.Hobbies[x].IsSelected, Model.Hobbies[x].Name) #:
#Html.HiddenFor(p => p.Hobbies[x].Name)
}
<span id="Hobbies-error" class="field-validation-error">
<span>Select any hobbies.</span>
</span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<b>Is Adult</b><br />
<label>
<span>Yes</span> #Html.RadioButtonFor(model => model.IsAdult, "true", new { style = "width:20px;" })
<span>No</span>#Html.RadioButtonFor(model => model.IsAdult, "false", new { style = "width:20px;" })
</label>
</div>
<div class="col-md-offset-2 col-md-10">
<label>
Enter Age #Html.TextBoxFor(model => model.Age)
</label>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<label>
#Html.HiddenFor(model => model.ErrorMsg)
#Html.ValidationMessageFor(model => model.ErrorMsg, "", new { #class = "text-danger" })
</label>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Submit" class="btn btn-default" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#if (ViewBag.IsPostBack != null && ViewBag.IsPostBack)
{
<text>
<b>Your Selected Product ID :</b> #ViewBag.ProductID<br />
<b>Your Selected Product Name :</b> #ViewBag.ProductName<br />
<b>Gender :</b> #ViewBag.Gender<br />
<b>Hobbies :</b> #ViewBag.Hobbies <br />
<b>Is Adult :</b> #ViewBag.IsAdult <br />
<b>Age :</b> #ViewBag.Age <br />
</text>
}
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
//$.validator.unobtrusive.adapters.add('customvalidation', ['productname', 'hashobby', 'isadult', 'age'], function (options) {
$.validator.unobtrusive.adapters.add('customvalidation', ['productname'], function (options) {
options.rules['customvalidation'] = { productname: options.params.productname };
});
$.validator.addMethod("customvalidation", function (value, element, param) {
alert(param.productname);
return false;
});
</script>
}

How to create view for given model

I am new to asp .net mvc 4.0. i have given model. i am not getting how can i create view for model. I am facing problem at IList JournalEntries. other entry i am able to do.
public class Journal : BaseClass
{
public virtual string VoucherNo { get; set; }
public virtual DateTime VoucherDate { get; set; }
public string VoucherDateView {
get
{
return VoucherDate.ToShortDateString();
}
}
public IList<JournalEntry> JournalEntries { get; set; }
public IList<Ledger> Accounts { get; set; }
public double TotalAmount
{
get
{
double sum = 0;
if (JournalEntries != null && JournalEntries.Count>0)
foreach (var journal in JournalEntries)
sum = journal.Principal + journal.Interest+sum;
return sum;
}
}
}
I have tried below view but add entry doesn't works.
#model Sms.CoreSociety.Journal
#{
ViewBag.Title = "Create";
}
#{
string data = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model);
}
<script type="text/javascript">
$(document).ready(function () {
$('#document').validate();
$("#VoucherDate").mask("99/99/9999", { placeholder: " " });
function entryVm(entries) {
var self = this;
self.entryList = ko.observableArray(entries);
self.entry = ko.observable();
self.rowClick = function(entry1) {
alert("Delete alert");
self.dispatchList.remove(entry1);
};
self.addEntry = function() {
alert("Add alert");
this.entryList.push({ AccountName_AccountHead: "", DebitCredit: "", Principal: "0.0", Interest: "0.0", Narration: ""});
};
}
var models = #Html.Raw(Json.Encode(Model.JournalEntries)) ;
ko.applyBindings(new entryVm(models));
});
</script>
#using (Html.BeginForm(null, null, FormMethod.Post, new Dictionary<string, object>() { { "class", "form-horizontal" }, { "id", "document" } }))
{
#Html.ValidationSummary(true)
<fieldset>
<div class="row">
<div class="span1">
<label>Voucher No</label>
</div>
<div class="span5">
#Html.DisplayFor(model => model.VoucherNo)
</div>
</div>
<div class="row">
<div class="span1">
<label>Voucher Date</label>
</div>
<div class="span5">
#Html.TextBoxFor(model => model.VoucherDate, "{0:dd/MM/yyyy}", new Dictionary<string, object>() { { "class", "required" } })
</div>
</div>
<div class="row">
<div class="span1">
<label>Amount</label>
</div>
<div class="span5">
#Html.DisplayFor(model => model.TotalAmount)
</div>
</div>
<input type="submit" value="Save" class="btn" id="submit"/>
#if (Model.Id != new Guid())
{
<div style="float: right">
<a class="btn btn-danger" href='#Url.Action("Delete")/#Model.Id' aria-hidden="true">Delete</a>
</div>
}
</fieldset>
}
<h4>Journal Entry</h4>
<p >Entry for<span data-bind="text: entryList().length"> </span> entry(s)</p>
<button data-bind="click: addEntry" class="btn">Add Record</button>
<table>
<tbody data-bind="template: { name: 'entryRowTemplate', foreach: entryList }"></tbody>
</table>
<script type="text/html" id="entryRowTemplate">
<tr>
<td>AccountName_AccountHead: \$ <input data-bind="value: AccountName.AccountHead"/> </td>
<td>DebitCredit: \$ <input data-bind="value: DebitCredit"/></td>
<td>Principal: \$ <input data-bind="value: Principal"/></td>
<td>Interest: \$ <input data-bind="value: Interest"/></td>
<td>Narration: \$ <input data-bind="value: Narration"/></td>
<td>Delete</td>
</tr>
</script>
below is my Journal controller
using System;
using System.Linq;
using System.Web.Mvc;
using Sms.CoreSociety;
using System.Collections.Generic;
namespace SmsModernUI.Controllers
{
public class JournalController : BaseController
{
//
// GET: /AccountGroup/
public ActionResult Index()
{
var journals = Repository.GetAll<Journal>().OrderBy(x => x.VoucherNo);
return View(journals);
}
public ActionResult Create(Guid id)
{
if (id == new Guid())
{
var journal = new Journal();
string lastvoucherno = Repository.GetAll<Journal>().OrderBy(x => x.VoucherNo).Last().VoucherNo;
journal.VoucherNo = (int.Parse(lastvoucherno) + 1).ToString();
journal.VoucherDate = System.DateTime.Now;
journal.JournalEntries = new List<JournalEntry>();
journal.Accounts = Repository.GetAll<Ledger>();
return PartialView(journal);
}
var journal1 = Repository.Get<Journal>(id);
journal1.JournalEntries = Repository.GetAll<JournalEntry>(x => x.Journal.Id == id);
journal1.Accounts = Repository.GetAll<Ledger>();
return PartialView(journal1);
}
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(Journal journal)
{
if (journal.Id == new Guid())
{
var jj = Repository.Save(journal);
foreach (var journalentry in journal.JournalEntries)
{
journalentry.Id = jj.Id;
Repository.Save(journalentry);
}
}
else
{
Journal jr = Repository.Get<Journal>(journal.Id);
var entries = Repository.GetAll<JournalEntry>(x=>x.Journal.Id == journal.Id);
foreach (var entry in entries)
{
Repository.Delete(entry);
}
var jj = Repository.Save(journal);
foreach (var journalentry in journal.JournalEntries)
{
journalentry.Id = jj.Id;
Repository.Save(journalentry);
}
}
return RedirectToAction("Index");
}
public ActionResult Index1()
{
Journal journal1 = Repository.Get<Journal>(new Guid("7A6EEBBC-2F3A-4A27-ACF8-A1D40115A68F"));
journal1.JournalEntries = Repository.GetAll<JournalEntry>(x => x.Journal.Id == journal1.Id);
journal1.Accounts = Repository.GetAll<Ledger>();
return View(journal1);
}
public ActionResult Delete(Guid id)
{
Journal jr = Repository.Get<Journal>(id);
var entries = Repository.GetAll<JournalEntry>(x => x.Journal.Id == jr.Id);
foreach (var entry in entries)
{
Repository.Delete(entry);
}
var result = Repository.Delete(jr);
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Create1(Journal journal)
{
var temp = journal;
return RedirectToAction("Create",journal.Id);
}
}
}
Views are not genereted from models. You need Controller Action method to pass your model to View.
public ActionResult()
{
var model = new Journal
{
//**define here value of model's properties, that you need in View
}
return View(model);
}
EDITED: After your addition.
I would devide it into two parts. Create ViewModel and pass it from View To Controller.
public JurnalViewModel
{
public Journal journal {get; set;}
public IList<JournalEntry> JournalEntries {get; set;}
}
Than in Create action first create journal and after foreach JournalEntries in model create new JournalEntry.
EDITED 2 To your comment. Quick sample:
[HttpPost]
public ActionResult Create (JurnalViewModel model)
{
var journal = new Journal();
db.Journals.Add(journal);
journal.name = model.journal.name
.....
//**some code
db.SaveChanges()
foreach(var item in model.JournalEntries )
{
var entry = new JournalEntry()
db.JournalEntries .Add(entry);
entry.property = item.property;
....
//**some code
db.SaveChanges()
}
}
Your problem is that you have no class constructor for JournalEntries.
public Journal()
{
JournalEntries = new List<JournalEntry>();
Accounts = new List<Ledger>();
}
Right click to your Action method inside controller and click add view then check create strongly typed-view checkbox then choose your desired model from dropdown in displayed dialogue box

test is null in the controller upon post

I have the following codes and the test value is always null in the controller after the post. What is wrong with the following code:
Model:
public class Suitcase
{
public string Color { get; set; }
public string[] Size { get; set; }
public List<string> Clothes { get; set; }
public List<Test> test { get; set; }
}
public class Test
{
public string Name { get; set; }
public int ID { get; set; }
}
The view:
<fieldset>
<legend>All about my baggage</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.Color) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Color) %>
</div>
<br />
<div class="editor-label">
Width, Height, Depth:
</div>
<div class="editor-field">
ml.TextBoxFor(model => model.Depth, new { style = "width:50px;" })%>
</div>
<br />
<div class="editor-label">Suitcase Contents</div>
<div class="editor-field">
<div id="clothes-editor">
Clothing Item: <input type="text" id="new-clothes-item" style="width:150px" /> <button id="add-clothes">Add to suitcase</button>
</div>
<b>Items currently in suitcase:</b>
<ul id="clothes-list">
</ul>
</div>
<p>
<button id="pack-it">Put on Baggage Carosel</button>
</p>
</fieldset>
<script type="text/javascript" language="javascript">
$(function () {
$("button").button();
// allow users to add items to the suitcase
$("#add-clothes").click(function () {
var clothesText = $("#new-clothes-item");
$("#clothes-list").append("<li>" + clothesText.val() + "</li>");
clothesText.val("").focus();
});
// pack the suitcase up and send it to the baggage carosel...erm...controller
$("#pack-it").click(function () {
var clothesList = [];
$("#clothes-list li").each(function () {
clothesList.push($(this).text())
});
var SizeList = [];
SizeList[0] = "Medium";
SizeList[1] = "Large";
SizeList[2] = "small";
var Data = new Object();
Data.test = [];
var reading = {};
reading.Name = "Micheal"
reading.ID = 123;
Data.test[0] = reading;
reading.Name = "Rowen"
reading.ID = 1234;
Data.test[1] = reading;
$.ajax({
type: 'POST',
traditional: true,
data: {
Color: $("#Color").val(),
Size: SizeList,
Clothes: clothesList,
test: Data.test
}
});
});
});
</script>
Controller:
[HttpPost]
public EmptyResult Suitcase(Suitcase lookWhatIPacked)
{
return new EmptyResult();
}
It's probably not related, but I don't think this code is doing what you intend:
var reading = {};
reading.Name = "Micheal"
reading.ID = 123;
Data.test[0] = reading;
reading.Name = "Rowen"
reading.ID = 1234;
Data.test[1] = reading;
This is adding the same object to Data.test twice, as you don't set reading to be a new array, so you're updating the original object to have "Rowen" as the Name and 1234 as the ID.

Resources