test is null in the controller upon post - asp.net-mvc

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.

Related

How to get items in cascade selectList after posting in ASP Core 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:

Syncfusion Blazor ListBox Template

I recently started using Syncfusion Blazor, but I'm having trouble understanding how the Template feature of the Listbox functions. I am trying to dynamically add components to a Listbox and pass the index of each new addition to the component. However, when I add a new component, all the indexes in the previous components also get updated. I need to be able to set the index for just one component.
#page "/test"
#using Syncfusion.Blazor.Buttons
#using Syncfusion.Blazor.DropDowns
<div class="container px-5">
<SfButton #onclick="AddMedia">Add Media</SfButton>
<SfListBox TValue="int[]" DataSource="#Data" TItem="ViewMedia" #ref="MediaListBoxObj">
<ListBoxFieldSettings></ListBoxFieldSettings>
<ListBoxTemplates TItem="ViewMedia">
<ItemTemplate>
<MediaCard media="new ViewMedia { ListIndex = MediaCount }" ></MediaCard>
</ItemTemplate>
</ListBoxTemplates>
<ListBoxSelectionSettings Mode="SelectionMode.Single"></ListBoxSelectionSettings>
</SfListBox>
</div>
#code {
// public ListData Model = new ListData();
SfListBox<int[], ViewMedia> MediaListBoxObj;
public List<ViewMedia> Data = new List<ViewMedia>
{
new ViewMedia{ ListIndex = 0}
};
int MediaCount = 0;
public List<ViewMedia> NewMediaItem { get; set; } = new List<ViewMedia>();
public List<ViewMedia> NewMedia()
{
NewMediaItem.Add(new ViewMedia { ListIndex = MediaCount});
return NewMediaItem;
}
private void AddMedia()
{
var newMediaItem = NewMedia();
MediaListBoxObj.AddItems(newMediaItem);
Data.Add(newMediaItem[0]);
MediaCount++;
NewMediaItem.Clear();
}
My MediaCard file:
<div class="AddMedia">
<div name="mediaAdd" class="container-fluid px-4">
<div class="form-row align-middle mb-2 pl-1">
<SfTextBox CssClass="e-filled" Placeholder="Provide a brief description" #bind-Value="media.Blurb"></SfTextBox>
</div>
<div class="form-row">
<label class="form-check-label">
Is there any blood or gore in the video?<span class="text-danger ml-1">*</span>
</label>
<div class="row">
<div class="form-check m-2 d-inline">
<SfRadioButton Label="No" Name="#media.ListIndex.ToString()" Value="0" Checked="#media.Gore"></SfRadioButton>
</div>
<div class="form-check m-2 d-inline">
<SfRadioButton Label="Yes" Name="#media.ListIndex.ToString()" Value="1" Checked="#media.Gore"></SfRadioButton>
</div>
</div>
</div>
</div>
</div>
#code {
[Parameter]
public ViewMedia media { get; set; }
}
I asked this question on the Syncfusion forums, and they got back to me with the following code which uses Observable Collection:
<div class="container px-5">
<SfButton #onclick="AddMedia">Add Media</SfButton>
<SfListBox TValue="int[]" DataSource="#Data" TItem="ViewMedia" #ref="MediaListBoxObj">
<ListBoxFieldSettings></ListBoxFieldSettings>
<ListBoxTemplates TItem="ViewMedia">
<ItemTemplate>
#{
var data = (context as ViewMedia);
<MediaCard media="new ViewMedia { ListIndex = data.ListIndex }"></MediaCard>
}
</ItemTemplate>
</ListBoxTemplates>
<ListBoxSelectionSettings Mode="SelectionMode.Single"></ListBoxSelectionSettings>
</SfListBox>
</div>
#code {
SfListBox<int[], ViewMedia> MediaListBoxObj;
public ObservableCollection<ViewMedia> Data { get; set; }
int MediaCount = 0;
protected override void OnInitialized()
{
this.Data = ViewMedia.getListData();
}
private void AddMedia()
{
MediaCount++;
this.Data.Add(new ViewMedia() { ListIndex = MediaCount });
}
public class ViewMedia
{
public int ListIndex { get; set; }
public int Gore { get; set; }
public string Blurb { get; set; }
public static ObservableCollection<ViewMedia> getListData()
{
ObservableCollection<ViewMedia> Data = new ObservableCollection<ViewMedia>();
Data.Add(new ViewMedia() { ListIndex = 0 });
return Data;
}
}
In case the above link fails, the above code can be downloaded here

Display a list in a partial view at post

I have this code in my controller:
[HttpPost]
public ActionResult Index(double userLat, double userLng)
{
var context = new weddingspreeEntities();
var coordinates = context.Venues
.Select(loc => new { vname = loc.VenueName, lat = loc.VenueLat, lng = loc.VenueLong })
.ToList();
string venueName = string.Empty;
List<SearchModel.DistLocation> venDistList = new List<SearchModel.DistLocation>();
for (int i = 0; i < coordinates.Count; i++)
{
string name = coordinates[i].vname;
double? lat = coordinates[i].lat;
double? lng = coordinates[i].lng;
var loc1Lat = lat.Value;
var loc1Lng = lng.Value;
var loc2Lat = userLat;
var loc2Lng = userLng;
double distance = TrackingHelper.CalculateDistance(
new SearchModel.Location() { Latitude = loc1Lat, Longitude = loc1Lng },
new SearchModel.Location() { Latitude = loc2Lat, Longitude = loc2Lng });
//convert kilometers to miles
double distMiles = distance * 0.621371192;
venueName = name;
venDistList.Add(new SearchModel.DistLocation() { venName = name, Distance = distMiles });
}
return View(venDistList);
}
I have this code in my view:
<div class="row">
<div class="form-group">
<div class="col-md-6">
#using (Html.BeginForm("Search", "Home", FormMethod.Post))
{
#*#Html.TextBoxFor(model => model.cityName)*#
<label>Enter City and State or Zip Code</label>
<input type="text" id="citystate" name="citystate" />
<label>Enter Your Wedding Date</label>
<input class="datefield" data-val="true" data-val-required="Date is required" id="weddingDate" name="weddingDate" type="date" value="1/11/1989" />
<label>Enter Your Guest Count</label>
<input type="text" id="guestcount" name="guestcount" />
<input type="button" id="search" name="search" value="Search for Venues" />
}
</div>
<!--This is the div where the google map will render -->
<div class="col-md-6">
<div id="map_canvas" style="height: 600px;"></div>
</div>
</div>
</div>
<div>
#Html.Partial("_SearchResults")
</div>
I have omitted some of my view for brevity
This is the partial view I am trying to render:
#model IEnumerable<WeddingSpree_Alpha.Models.SearchModel.DistLocation>
#{
Layout = null;
}
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
foreach (var item in Model)
{
#item.venName
#item.Distance
}
}
What I am trying to do is to have the user enter the values in the search box and then after the click post the results (in the list named venDistList) to the view using a foreach statement.
The model looks like this:
public class SearchModel
{
public string cityName { get; set; }
public DateTime weddingDate { get; set; }
public int guestCount { get; set; }
public class Location
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class DistLocation
{
public string venName { get; set; }
public double Distance { get; set; }
}
}
I would like the list results to populate after the button click (post) on the page. I thought my code would do that however. I get the following error:
System.NullReferenceException: 'Object reference not set to an instance of an object'
I know that error happens when you try to use a model that is not populated yet but I thought I did that in my controller code? What exactly could be throwing that error?
This is the controller code for my partial view:
public ActionResult _SearchResults(SearchModel model)
{
return View();
}
If you are not at least instantiating an instance of IEnumerable to pass back (even if it is empty) then it will throw the null reference when you try to iterate throught the model in the partial view.
Edit: (Code trimmed down for example) Your original error is that you are trying to iterate through an object that does not exist. The below will show you how to make user of an Ajax call on your form submit to dynamically generate your partial view and attach it to your main page
Controller:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult _SearchResults(string citystate, DateTime? weddingDate, double? guestcount)
{
List<SearchModel.DistLocation> venDistList = new List<SearchModel.DistLocation>();
venDistList.Add(new SearchModel.DistLocation() { venName = "weee1", Distance = 2 });
venDistList.Add(new SearchModel.DistLocation() { venName = "weee2", Distance = 4 });
venDistList.Add(new SearchModel.DistLocation() { venName = "weee3", Distance = 6 });
return PartialView(venDistList);
}
Index.cshtml:
#{
ViewBag.Title = "Home Page";
}
#*This is our form which will feed our user input and drive our search results output*#
<div class="row">
<div class="form-group">
<div class="col-md-6">
<form id="searchMe">
<label>Enter City and State or Zip Code</label>
<input type="text" id="citystate" name="citystate" />
<label>Enter Your Wedding Date</label>
<input class="datefield" data-val="true" data-val-required="Date is required" id="weddingDate" name="weddingDate" type="date" value="1/11/1989" />
<label>Enter Your Guest Count</label>
<input type="text" id="guestcount" name="guestcount" />
<button type="submit" class="btn btn-primary">Search for Venues</button>
</form>
</div>
</div>
</div>
<div class="row">
#*This is where we want our search results to appear when user hits submit on our form*#
<div id="SearchResult"></div>
</div>
#section scripts {
<script>
$(document).ready(function () {
//When the user hit the submit button we will post the form results to our partial view controller
$('#searchMe').submit(function () {
$.ajax({
method: "POST",
url: "/Home/_SearchResults",
data: $(this).serialize(),
success: function (result) {
//When then load our partial view into our containing div on the main page
$('#SearchResult').html(result);
}
});
return false;
});
});
</script>
}
Partial View (_SearchResult.cshtml)
#model IEnumerable<deletemeweb2.Models.SearchModel.DistLocation>
#{
Layout = null;
}
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Search Results</h3>
</div>
<div class="panel-body">
#if (Model != null || Model.Count() < 1)
{
using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
foreach (var item in Model)
{
<p>#item.venName</p>
<p>#item.Distance</p>
}
}
}
else
{
<p>No results found</p>
}
</div>
</div>

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

Resources