knockout.js binding issue when trying to refresh data - asp.net-mvc-4

I am using knockout.js data binding. At the page load the binding works fine and data is shown on the page correctly. Then I try to push data back to the database and the push is successful. The database receives the data OK.
The problem comes when I try to reload the data upon push success. At this time the binding already happen once (at the page load). If I don't bind it again the data on the page does not refresh. If I do the binding again knockout.js issues an error "cannot bind multiple times". If I do a cleanup before rebinding I receive an error "nodeType undefined".
Can anyone tell me what I have missed here? I am using ASP.NET MVC 4.0 with knockout.js 3.0.0.
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplJSON.Controllers
{
public class KnockoutController : Controller
{
//
// GET: /Knockout/
public ActionResult Index()
{
return View();
}
[HttpGet]
public JsonResult GetProductList()
{
var model = new List<Product>();
try
{
using (var db = new KOEntities())
{
var product = from p in db.Products orderby p.Name select p;
model = product.ToList();
}
}
catch (Exception ex)
{ throw ex; }
return Json(model, JsonRequestBehavior.AllowGet);
}
// your controller action should return a JsonResult. There's no such thing as a controller action that returns void. You have specified dataType: 'json' so return JSON. That's it. As far as what parameter this controller action should take, well, from the JSON you are sending ({"Name":"AA"}) it should be a class that has a Name property of type string.
// modify your action signature to look like this: [HttpPost] public ActionResult SaveProduct (Product product) { ... return Json(new { success = true }); }. Or get rid of this dataType: 'json' attribute from your AJAX request if you don't want to return JSON. In this case you could return simply status code 201 (Created with empty response body): return new HttpStatusCodeResult(201);.
[HttpPost]
public ActionResult SaveProduct(Product product)
{
using (var db = new KOEntities())
{
db.Products.Add(new Product { Name = product.Name, DateCreated = DateTime.Now });
db.SaveChanges();
}
return Json(new { success = true });
}
}
}
View:
#{
ViewBag.Title = "Knockout";
}
<h2>Knockout</h2>
<h3>Load JSON Data</h3>
<div id="loadJson-custom" class="left message-info">
<h4>Products</h4>
<div id="accordion" data-bind='template: { name: "product-template", foreach: product }'>
</div>
</div>
<h3>Post JSON Data</h3>
<div id="postJjson-custom" class="left message-info">
<h4>Add Product</h4>
<input id="productName" /><br />
<button id="addProduct">Add</button>
</div>
#section Scripts {
#Scripts.Render("~/bundles/knockout")
#Scripts.Render("~/bundles/livequery")
<script src="/Scripts/jquery.livequery.min.js"></script>
<style>
#accordion { width: 400px; }
</style>
<script id="product-template" type="text/html">
<h3><a data-bind="attr: {href:'#', title: Name, class: 'product'}"><span data-bind="text: Name"></span></a></h3>
<div>
<p>Here's some into about <span data-bind="text: Name" style="font-weight: bold;"></span> </p>
</div>
</script>
<script>
var isBound;
function loadJsonData() {
$.ajax({
url: "/knockout/GetProductList",
type: "GET",
contentType: "application/json",
dataType: "json",
data: {},
async: true,
success: function (data) {
var loadJsonViewModel = {
product: ko.observableArray(),
init: function () {
loadAccordion();
}
};
var a = $('loadJson-custom');
loadJsonViewModel.product = ko.mapping.fromJS(data);
if (isBound) { }
else
{
ko.applyBindings(loadJsonViewModel, $('loadJson-custom')[0]);
isBound = true;
}
loadJsonViewModel.init();
}
});
}
// push data back to the database
function pushJsonData(productName) {
var jData = '{"Name": "' + productName + '"}';
$.ajax({
url: "/knockout/SaveProduct",
type: "POST",
contentType: "application/json",
dataType: "json",
data: jData,
async: true,
success: function (data, textStatus, jqXHR) {
console.log(textStatus + " in pushJsonData: " + data + " " + jqXHR);
//ko.cleanNode($('loadJson-custom')[0]);
loadJsonData();
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus + " in pushJsonData: " + errorThrown + " " + jqXHR);
}
});
}
function loadAccordion() {
$("#accordion > div").livequery(function () {
if (typeof $("#accordion").data("ui-accordion") == "undefined")
{
$("#accordion").accordion({ event: "mouseover" });
}
else
{
$("#accordion").accordion("destroy").accordion({ event: "mouseover" });
}
});
}
$(function () {
isBound = false;
loadJsonData();
$("#addProduct").click(function () {
pushJsonData($("#productName").val());
});
});
</script>
}

Here is a complete solution for your question.
I have just implemented and checked.
Please have a look.
I have created a class for getting some records ie: Records.cs.
public static class Records
{
public static IList<Student> Stud(int size)
{
IList<Student> stud = new List<Student>();
for (int i = 0; i < size; i++)
{
Student stu = new Student()
{
Name = "Name " + i,
Age = 20 + i
};
stud.Add(stu);
}
return stud;
}
}
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
Here is a controller for the respective view.
//
// GET: /HelpStack/
private static IList<Student> stud = Records.Stud(10);
public ActionResult HelpStactIndex()
{
return View();
}
[HttpGet]
public JsonResult GetRecord()
{
return Json(stud, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public void PostData(Student model)
{
//do the required code here as All data is in "model"
}
Here is a view as HTML, I have taken two section one for list and other to Add records
<div id="loadJson-custom">
<h4>Student</h4>
<table width="100%">
<tr>
<td style="width: 50%">
<div id="accordion" data-bind='template: { name: "product-template", foreach: Student }'>
</div>
</td>
<td valign="top">
<div id="NewStudent">
<input type="text" data-bind="value: Name" /><br />
<input type="number" data-bind="value: Age" /><br />
<input type="submit" data-bind="click: Save" value="AddNew" />
</div>
</td>
</tr>
</table>
Here is your scripts for Knockoutjs.
<script id="product-template" type="text/html">
<h3><a data-bind="attr: { href: '#', title: Name, class: 'product' }"><span data-bind=" text: Name"></span></a>
<br />
Age: <span data-bind="text: Age"></span>
</h3>
<div>
<p>Here's some into about <span data-bind="text: Name" style="font-weight: bold;"></span></p>
</div>
</script>
<script type="text/javascript">
//Model for insert new record
var Model = {
Name: ko.observable(''),
Age: ko.observable(''),
};
var Student = ko.observableArray([]); // List of Students
function loadData() { //Get records
$.getJSON("/HelpStack/GetRecord", function (data) {
$.each(data, function (index, item) {
Student.push(item);
});
}, null);
}
function Save() { //Save records
$.post("/HelpStack/PostData", Model, function () { //Oncomplete i have just pushed the new record.
// Here you can also recall the LoadData() to reload all the records
//Student.push(Model);
Student.unshift(Model); // unshift , add new item at top
});
}
$(function () {
loadData();
ko.applyBindings(Model, $('#NewStudent')[0]);
});
</script>

You are declaring your model inside loadJsonData function success callback, & creating new object on every success callback, move the model outside that function, create an object & use it inside loadJsonData function, it will fix the issue.

Related

.NET & Vue API communication through [FromForm]

I'm trying to send a list of object in which contains IFormFile.
Here are my object :
public class ImageGalleryDto
{
public Guid? PageId { get; set; }
public int? Order { get; set; }
public IFormFile? Image { get; set; }
}
My endpoint in .net core :
public async Task<EndpointResult<object>> UpdateImageGallery([FromForm] List<ImageGalleryDto> imageGalleryDto)
My object in vue is exactly same as with this model. And I'm trying to send like this in vue.js
const formData = new FormData();
formData.append("imageGalleryDto", pushToApi);
this.updateImageGallery(formData).then((res) => {....}
Unfortunately, in the controller, the list is empty when it is called.
According to your description, it looks like there is something wrong with your formdata, the formdata should like below, then the asp.net core model binding will auto bind the data to the model inside the web api controller.
const formData = new FormData();
this.images.forEach((image, index) => {
formData.append(`imageGalleryDto[${index}].pageId`, image.pageId);
formData.append(`imageGalleryDto[${index}].order`, image.order);
formData.append(`imageGalleryDto[${index}].image`, image.image);
});
The details example like below:
Since you have vue.js tag, I use vue.js example
Client:
<div id="app">
<image-upload-form></image-upload-form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.min.js"></script>
<script>
Vue.component('image-upload-form', {
template: `
<div>
<form #submit.prevent="uploadImages" enctype="multipart/form-data">
<div v-for="(image, index) in images" :key="index">
<input type="text" v-model="image.pageId" :name="'images[index].pageId'" placeholder="Page ID"/>
<input type="number" v-model="image.order" :name="'images[index].order'" placeholder="Order"/>
<input type="file" ref="file" :name="'images[index].image'" #change="onFileChange(index,$event)" />
</div>
<button type="submit">Upload Images</button>
</form>
</div>
`,
data() {
return {
images: [{ pageId: '', order: '', image: null }, { pageId: '', order: '', image: null }]
};
},
methods: {
onFileChange(index, event) {
this.images[index].image = event.target.files[0];
},
async uploadImages() {
const formData = new FormData();
this.images.forEach((image, index) => {
formData.append(`imageGalleryDto[${index}].pageId`, image.pageId);
formData.append(`imageGalleryDto[${index}].order`, image.order);
formData.append(`imageGalleryDto[${index}].image`, image.image);
});
try {
const response = await fetch('https://localhost:7204/api/values/upload', {
method: 'POST',
body: formData
});
if (response.ok) {
console.log('Images uploaded successfully');
} else {
console.error('Failed to upload images');
}
} catch (error) {
console.error('Error uploading images', error);
}
}
}
});
new Vue({
el: '#app'
});
</script>
Backend:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpPost("upload")]
public async Task<IActionResult> UploadImages([FromForm] List<ImageGalleryDto> imageGalleryDto)
{
// Do something with the imageGalleryDtos object
return new JsonResult("OK");
}
Result:

how to get data from database using ajax asp.net core

According to the following codes i have created the Get Handler in Index Model
public IActionResult OnGetCustomer(CustomerSearchModel searchModel)
{
CustomerCombine combine = new CustomerCombine
{
MyViewModels = _customerApplication.GetAll(searchModel)
};
return Partial("./Customer", combine);
}
and this is my Razor View:
#model CustomerCombine
<form asp-page="./Index" asp-page-handler="Customer"
method="get"
data-ajax="true"
data-callback=""
data-action="Refresh"
>
<div class="form-group">
<input asp-for="#Model.MySearchModel.FullName" class="form-control " placeholder="search..." />
</div>
<button class="customer-submit btn btn-success" type="submit">جستجو</button>
</form>
<table>
#foreach (var item in #Model.MyViewModels)
{
<tr>
<td>#item.Id</td>
<td>#item.FullName</td>
<td>#item.Mobile</td>
<td>#item.Email</td>
<td>#item.Address</td>
<td>#item.Image</td>
</tr>
}
</table>
My modal is displayed successfully,and i can see my database's data, but when i fill search field and click on search button , nothing happens
can any one help me plz?:)
and this is my jquey codes: i dont anything about Jquery and these codes were ready and now i dont knoe how i should use from it
$(document).on("submit",
'form[data-ajax="true"]',
function (e) {
e.preventDefault();
var form = $(this);
const method = form.attr("method").toLocaleLowerCase();
const url = form.attr("action");
var action = form.attr("data-action");
if (method === "get") {
const data = form.serializeArray();
$.get(url,
data,
function (data) {
CallBackHandler(data, action, form);
});
} else {
var formData = new FormData(this);
$.ajax({
url: url,
type: "post",
data: formData,
enctype: "multipart/form-data",
dataType: "json",
processData: false,
contentType: false,
success: function (data) {
CallBackHandler(data, action, form);
},
error: function (data) {
alert("خطایی رخ داده است. لطفا با مدیر سیستم تماس بگیرید.");
}
});
}
return false;
});
});
function CallBackHandler(data, action, form) {
switch (action) {
case "Message":
alert(data.Message);
break;
case "Refresh":
if (data.isSucceced) {
window.location.reload();
} else {
alert(data.message);
}
break;
case "RefereshList":
{
hideModal();
const refereshUrl = form.attr("data-refereshurl");
const refereshDiv = form.attr("data-refereshdiv");
get(refereshUrl, refereshDiv);
}
break;
case "setValue":
{
const element = form.data("element");
$(`#${element}`).html(data);
}
break;
default:
}
}
function get(url, refereshDiv) {
const searchModel = window.location.search;
$.get(url,
searchModel,
function (result) {
$("#" + refereshDiv).html(result);
});
}
1.The third parameter of $.get() is the success function.
2.There is no isSucceced property in your postback data. The postback data is the partial view html code. You need use $("xxx").html(data); to update the partial view code.
3.Model Binding binds the property by name, <input asp-for="#Model.MySearchModel.FullName"/> does not match the CustomerSearchModel searchModel.
public IActionResult OnGetCustomer(CustomerSearchModel MySearchModel)
Whole working demo and more details I have commented on the code pls check carefully:
Model
public class CustomerCombine
{
public List<MyViewModel> MyViewModels { get; set; }
public CustomerSearchModel MySearchModel { get; set; }
}
public class CustomerSearchModel
{
public string FullName { get; set; }
}
public class MyViewModel
{
public int Id { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public string Address { get; set; }
public string Image { get; set; }
}
View(Index.cshtml)
#page
#model IndexModel
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
#Html.Partial("Customer",Model.CustomerCombine)
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
#section Scripts
{
<script>
$(document).on("submit",'form[data-ajax="true"]',function (e) {
e.preventDefault();
var form = $(this);
const method = form.attr("method").toLocaleLowerCase();
const url = form.attr("action");
var action = form.attr("data-action");
if (method === "get") {
const data = form.serializeArray();
$.get(url,data,function (data) {
console.log(data); //you can check the response data in Console panel
CallBackHandler(data, action, form);
});
} else {
var formData = new FormData(this);
$.ajax({
url: url,
type: "post",
data: formData,
enctype: "multipart/form-data",
dataType: "json",
processData: false,
contentType: false,
success: function (data) {
CallBackHandler(data, action, form);
},
error: function (data) {
alert("خطایی رخ داده است. لطفا با مدیر سیستم تماس بگیرید.");
}
});
}
return false;
});
//}); //remove this.......
function CallBackHandler(data, action, form) {
switch (action) {
case "Message":
alert(data.Message);
break;
case "Refresh":
$(".modal-body").html(data); //modify here....
break;
case "RefereshList":
{
hideModal();
const refereshUrl = form.attr("data-refereshurl");
const refereshDiv = form.attr("data-refereshdiv");
get(refereshUrl, refereshDiv);
}
break;
case "setValue":
{
const element = form.data("element");
$(`#${element}`).html(data);
}
break;
default:
}
}
function get(url, refereshDiv) {
const searchModel = window.location.search;
$.get(url,
searchModel,
function (result) {
$("#" + refereshDiv).html(result);
});
}
</script>
}
Partial View does not change anything
#model CustomerCombine
<form asp-page="./Index" asp-page-handler="Customer"
method="get"
data-ajax="true"
data-callback=""
data-action="Refresh"
>
<div class="form-group">
<input asp-for="#Model.MySearchModel.FullName" class="form-control " placeholder="search..." />
</div>
<button class="customer-submit btn btn-success" type="submit">جستجو</button>
</form>
<table>
#foreach (var item in #Model.MyViewModels)
{
<tr>
<td>#item.Id</td>
<td>#item.FullName</td>
<td>#item.Mobile</td>
<td>#item.Email</td>
<td>#item.Address</td>
<td>#item.Image</td>
</tr>
}
</table>
PageModel
public IActionResult OnGetCustomer(CustomerSearchModel MySearchModel)//change here....
{
CustomerCombine combine = new CustomerCombine
{
MyViewModels = _customerApplication.GetAll(searchModel) //be sure here contains value...
};
return Partial("./Customer", combine);
}
Result:

How to return a partial view and invoke the model's constructor with DI system

I have a parent view, and want to call a handler with ajax that will return a partial view. The problem I'm having is that my partial view needs it's model also which has all its own OnGet, OnPost etc methods.
When calling:
public PartialViewResult OnGetPartialView(Guid Id)
{
return Partial("MyPartialView");
}
I don't know how to add the model for this view, as its only constructor takes several services that usually the DI systems takes care of for me. I also need to pass the Id to the partial view as its used in the OnGet method (which I'm assuming will be invoked when this works properly).
Thanks!
To pass the model to the partial view in razor pages, you need to add the second parameter as the model you need to pass when returning to the Partial:
return Partial("MyPartialView", model);
It should be noted that in MyPartialView, you need to delete the #Page in the first line of the page and add the model reference you passed.
This will ensure that MyPartialView receives the model data, otherwise there will be an error that model is null.
Regarding the OnGet and OnPost methods of the MyPartialView page you mentioned, if you delete #Page, they will lose their actual contact meaning.
My suggestion is that if you have some post or get methods that need to be used in MyPartialView, you can write these methods to other pages.
Here is a complete example:
TestModel.cshtml.cs:
public class TestModel : PageModel
{
public void OnGet()
{
}
public PartialViewResult OnGetPartialView(Guid Id)
{
List<Person> persons = new List<Person>()
{
new Person(){ Age = 12,
FirstName = "dd",
LastName = "aa" },
new Person(){ Age = 13,
FirstName = "bb",
LastName = "ff" },
new Person(){ Age = 14,
FirstName = "ggr",
LastName = "rwe" },
};
return Partial("MyPartialView", persons);
}
public IActionResult OnPostTest()
{
return Content("aa");
}
}
TestModel.cshtml:
#page
#model WebApplication_razorpage_new.Pages.TestModel
#{
ViewData["Title"] = "Test";
Layout = "~/Pages/Shared/_Layout.cshtml";
}
<h1>Test</h1>
<input id="Button1" type="button" value="Get partial view" /><br /><br /><br />
<div id="partial" class="border"></div>
#section Scripts{
<script>
$(function () {
$("#Button1").click(function () {
$.ajax({
type: "get",
url: "/Test?handler=PartialView",
data: { Id: "780cd7ce-91b2-40fd-b4c8-7efa6b7c84a5" },
success: function (data) {
$("#partial").html(data);
}
});
});
})
</script>
}
MyPartialView.cshtml:
#model List<Person>
<form method="post">
<input id="Button1" type="button" value="button" onclick="Click()" />
<input id="Text1" type="text" />
<table class="table table-bordered">
#foreach (var item in Model)
{
<tr>
<td>#item.Age</td>
<td>#item.FirstName</td>
<td>#item.LastName</td>
</tr>
}
</table>
</form>
<script>
function Click() {
$.ajax({
type: "POST",
url: "/Test?handler=test",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
contentType: "application/json; charset=utf-8",
success: function (data) {
$("#Text1").val(data);
}
});
}
</script>
Here is the test result:

Loading Remote Data in Select2

I am using Select2's Loading Remote Data Functionality.The problem is that data is not getting loaded on the dropdownlist.On keypress remote function is getting called and data is returning properly,but its not showing in dropdownlist.
HTML
<div class=" form-group col-md-4" data-url="#Url.Action("GetStudentWalkInnName")" id="WalkinnName">
<div>
<label for="txtEmployee" class=" control-label">
Name
</label>
</div>
<div>
<select class="form-control " id="ddlName"></select>
</div>
</div>
Jquery
//REGISTRATION=>INDEX.JS
$(function () {
var ddlNameUrl=$("#WalkinnName").data("url");
$("#ddlName").select2({
placeholder: "Search for Name",
minimumInputLength: 1,
ajax: { // instead of writing the function to execute the request we use Select2's convenient helper
url: ddlNameUrl,
type: "POST",
dataType: 'json',
data: function (params) {
return {
term: params.term, // search term
page: params.page
};
},
processResults: function (data, params) {
params.page = params.page || 1;
return {
results: data,
};
}
}
});
});
Controller is
public JsonResult GetStudentWalkInnName(string term)
{
try
{
var walkInnNameList = _db.StudentWalkInns
.Where(s => s.CandidateName.StartsWith(term))
.Select(x => new
{
Id=x.Id,
Text=x.CandidateName
}).ToList();
return Json(walkInnNameList, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json("", JsonRequestBehavior.AllowGet);
}
}
Any help will be highly appreciated.
According to the documentation, the format if the data should be an array of objects with names id and name i.e. lowercase (not Id and Name).
Change you query to
var walkInnNameList = _db.StudentWalkInns
.Where(s => s.CandidateName.StartsWith(term))
.Select(x => new
{
id = x.Id,
text = x.CandidateName
}); // .ToList() should not be necessary

Add error message if duplicate record exist in MVC Popup Form

I have a popup window called AddNew will display when the user click a button called add New. The button itself has number of field called TRN and DOB. The problem that i have now that i am trying to display error message when the user try to add duplicate TRN but unfortunately no error message display only if the required field is empty.
Is there anyway i could display the duplicate error message in validation summary like displaying in required field and hold all the previous entered value in the form. Please advise. Thank you
Here is the code that i have so far. Thank you
Index.cshtml
<input type="button" id="btnAddNew" style="height:50px; font-size:14px; width:95px; background-color:#3399FF; white-space: normal;" class="k-button" title="AddNew" value="Add New" />
<script type="text/javascript">
$(document).ready(function () {
$('#btnAddNew').click(function () {
window.open('#Url.Action("AddNew", "Details")', 'AddProduct', 'height=' + (window.screen.height - 450) + ',width=950,left=' + (window.screen.width - 5) + ',top=10,status=no,toolbar=no,resizable=yes,scrollbars=yes');
});
});
</script>
AddNew.cshtml (window popup)
#{
Layout = "~/Views/Shared/_LayoutNoMenu.cshtml";
}
<script src="../../Scripts/jquery.validate.js" type="text/javascript"></script>
<script src="../../Scripts/jquery.validate.unobtrusive.js" type="text/javascript"></script>
#model HHIMS_Web_App.Models.CModel
#{
ViewBag.Title = "New Product";
}
#using (Html.BeginForm("Create", "Details", FormMethod.Post, new { id = "frmAsset" }))
{
ViewContext.FormContext.ValidationSummaryId = "valSumId";
#Html.ValidationSummary(false, "Please fix the following errors:", new Dictionary<string, object> { { "id", "valSumId" } });
<fieldset id="AddNew">
<div>
<div class="addInfo">
#Html.LabelFor(model => model.TRN)
#Html.EditorFor(model => model.TRN)
#Html.ValidationMessageFor(model => model.TRN, "*")
</div>
<div class="AddSmallBox">
#Html.LabelFor(model => model.DOB)
#Html.EditorFor(model => model.DOB)
#Html.ValidationMessageFor(model => model.DOB, "*")
</div>
</div>
<div>
<div class="smallAddAndCancel">
<input type="button" id="btnCancel" style="height:50px; width:85px; font-size:14px; background-color:#3399FF" class="k-button" title="Cancel" value="Cancel" onclick="window.close()" />
<input type="submit" id="btnSave" style="height:50px; width:85px; font-size:14px; background-color:#3399FF;white-space: normal" class="k-button" title="Save" value="Save"/>
</div>
</div>
</fieldset>
}
<script type="text/javascript">
$(document).ready(function () {
$("#datepicker").closest("span.k-datepicker").width(400);
$('#btnSave').click(function () {
var validation = $("#frmAsset");
if (!validation.valid()) {
return false;
else
{
$.ajax({
type: 'POST',
url: "#Url.Action("Create","Details")",
data: {
TRN: $("#TRN").val(),
DOB: $("#DOB").val(),
},
success: function () {
window.close()
}
});
}
});
});
</script>
Controller:
[HttpPost]
public ActionResult Create(Cmodel)
{
try
{
if (ModelState.IsValid)
{
CheckDuplicateHRNExist(model);
return RedirectToAction("AddNew");
}
if (ModelState.IsValid)
{
HH_DataAccessLayer.Consumers dalModel = new HH_DataAccessLayer.Consumers();
Mapper.CreateMap<CModel, HH_DataAccessLayer.Consumers>();
Mapper.Map(model, dalModel);
return RedirectToAction("Index");
}
}
catch (DbUpdateConcurrencyException e)
{
var entry = e.Entries.Single();
var clientValues = (CModel)entry.Entity;
}
return RedirectToAction("Index");
}
/// <summary>
/// Validate TRN find if no duplicate TRN recorded
/// </summary>
/// <param name="model"></param>
private void CheckDuplicateTRNExist(CModel model)
{
HEntities context = new HEntities();
if (model.TRN != null)
{
var duplicateTRN = context.Consumers.Where(d => d.TRN == model.TRN).FirstOrDefault();
if (duplicateTRN != null)
{
var errorMessage = String.Format("TRN is already exist.", duplicateTRN);
ModelState.AddModelError(string.Empty, errorMessage);
}
}
}
Model
[Required(ErrorMessage = "Please enter TRN")]
[DisplayName("TRN")]
[StringLength(20)]
public string TRN { get; set; }
[Required(ErrorMessage = "Please enter or select Date of Birth")]
[DisplayName("Date Of Birth")]
public DateTime? DOB { get; set; }
If I'm not mistaking, ValidationSummary must be set to true to display custom errors.
Edit: to be complete:
In your AddNew.cshtml file, replace
#Html.ValidationSummary(false, "Please fix the following errors:", new Dictionary<string, object> { { "id", "valSumId" } });
With:
#Html.ValidationSummary(true, "Please fix the following errors:", new Dictionary<string, object> { { "id", "valSumId" } });