How to avoid multiple submit of form in ASP.NET MVC? - c#

I tried to write a code and scripts using ASP.NET MVC 5. Was I use modal to do Create, Update, and Delete functionality which is working properly but when it comes with Creating, and Updating because I enable remote validations, it works at first but suddenly when you click again the submit button it will submit or post the data. In short, my validation is not working. Please, I need help.
Model:
[Key]
[Display(Name = "ID")]
[Column("LAND_TYPE_CAT_ID", Order = 0, TypeName = "bigint")]
public long CategoryId { get; set; }
[Display(Name = "Category Name")]
[StringLength(100)]
[Column("LAND_TYPE_CAT", Order = 1, TypeName = "nvarchar")]
public string CategoryName { get; set; }
[Display(Name = "Description")]
[StringLength(255)]
[Column("LAND_TYPE_CAT_DESC", Order = 2, TypeName = "nvarchar")]
public string CategoryDescription { get; set; }
[Display(Name = "Created Date")]
[Column("CREATE_DATE", Order = 3, TypeName = "datetime")]
public DateTime? CreateDate { get; set; }
[Display(Name = "Modified Date")]
[Column("MODIFIED_DATE", Order = 4, TypeName = "datetime")]
public DateTime? ModifiedDate { get; set; }
[Display(Name = "Last Modified By")]
[StringLength(255)]
[Column("LAST_MODIFIED_BY", Order = 5, TypeName = "nvarchar")]
public string LastModifiedBy { get; set; }
ViewModels:
For Create:
[Display(Name = "Category Name")]
[Required(ErrorMessage = "This field is required.")]
[Remote("ValidateCreate", "Category", ErrorMessage = "This type already exists.")]
public string CategoryName { get; set; }
For Update:
[Display(Name = "Category Name")]
[Required(ErrorMessage = "This field is required.")]
[Remote("ValidateEdit", "Category", AdditionalFields = "CategoryId, CategoryName",
ErrorMessage = "This type already exists.")]
public string CategoryName { get; set; }
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(LandTypeCategoryCreateViewModels viewModel)
{
if (ModelState.IsValid)
{
var vm = new LandTypeCategory
{
CategoryName = viewModel.CategoryName,
CategoryDescription = viewModel.CategoryDescription,
CreateDate = DateTime.Now,
LastModifiedBy = "Tester"
};
_context.LandTypeCategories.Add(vm);
await _context.SaveChangesAsync();
TempData["Created"] = "New category type added.";
var url = Url.Action("Index", "Category", new {id = viewModel.CategoryId});
return Json(new {success = true, url});
}
return PartialView("_Create", viewModel);
}
public async Task<ActionResult> Edit(long? id)
{
if (id == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var vm = await _context.LandTypeCategories.FindAsync(id);
if (vm == null)
return HttpNotFound();
var viewModel = new LandTypeCategoryEditViewModels
{
CategoryId = vm.CategoryId,
CategoryName = vm.CategoryName,
CategoryDescription = vm.CategoryDescription
};
return PartialView("_Edit", viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(LandTypeCategoryEditViewModels viewModel)
{
if (ModelState.IsValid)
{
var vm =
await _context.LandTypeCategories.SingleAsync(x => x.CategoryId == viewModel.CategoryId);
vm.CategoryName = viewModel.CategoryName;
vm.CategoryDescription = viewModel.CategoryDescription;
vm.ModifiedDate = DateTime.Now;
vm.LastModifiedBy = "Modify Tester";
_context.Entry(vm).State = EntityState.Modified;
await _context.SaveChangesAsync();
TempData["Updated"] = "Category type updated.";
var url = Url.Action("Index", "Category", new {id = viewModel.CategoryId});
return Json(new {success = true, url});
}
return PartialView("_Edit", viewModel);
}
Remote Validation:
public async Task<JsonResult> ValidateCreate(string CategoryName)
{
return
Json(
await _context.LandTypeCategories.AllAsync(
c => c.CategoryName.ToLower() != CategoryName.ToLower()), JsonRequestBehavior.AllowGet);
}
public async Task<JsonResult> ValidateEdit(int CategoryId, string CategoryName)
{
var category = await _context.LandTypeCategories.FindAsync(CategoryId);
var result = true;
if (category.CategoryName.ToLower() != CategoryName.ToLower())
result =
await _context.LandTypeCategories.AllAsync(
c => c.CategoryName.ToLower() != CategoryName.ToLower());
return Json(result, JsonRequestBehavior.AllowGet);
}
Index.cshtml
#model IEnumerable<MvcPPT.Models.LandTypeCategory>
#{
ViewBag.Title = "Category";
}
<div class="container">
<br />
<br />
<br />
#Html.ActionLink("Add New", "Create", "Category", new { ViewBag.CategoryId }, new { data_modal = "", #class = "btn btn-primary", style = "position: absolute;background-color: #3498db; border-color: #3498db;" })
<table class="table table-hover table-bordered" id="same-datatable" style="font-size: smaller; width: 100%;">
<thead>
<tr>
<th>#Html.DisplayNameFor(model => model.CategoryId)</th>
<th>#Html.DisplayNameFor(model => model.CategoryName)</th>
<th>#Html.DisplayNameFor(model => model.CategoryDescription)</th>
<th>#Html.DisplayNameFor(model => model.CreateDate)</th>
<th>#Html.DisplayNameFor(model => model.ModifiedDate)</th>
<th>#Html.DisplayNameFor(model => model.LastModifiedBy)</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.CategoryId)</td>
<td>#Html.DisplayFor(modelItem => item.CategoryName)</td>
<td>#Html.DisplayFor(modelItem => item.CategoryDescription)</td>
<td>#Html.DisplayFor(modelItem => item.CreateDate)</td>
<td>#Html.DisplayFor(modelItem => item.ModifiedDate)</td>
<td>#Html.DisplayFor(modelItem => item.LastModifiedBy)</td>
<td>
#Html.ActionLink("Edit", "Edit", "Category", new { id = item.CategoryId }, new { data_modal = "", #class = "btn btn-warning btn-xs" })
#Html.ActionLink("Delete", "Delete", "Category", new { id = item.CategoryId }, new { data_modal = "", #class = "btn btn-danger btn-xs" })
</td>
</tr>
}
</tbody>
</table>
</div>
<div id="myModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div id="myModalContent"></div>
</div>
</div>
</div>
_Create.cshtml
#model MvcPPT.ViewModels.LandTypeCategoryCreateViewModels
<div class="modal-header" style="background-color: #3498db; color: #fff;">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Add New Category Type</h4>
</div>
#using (Html.BeginForm())
{
<div class="modal-body">
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
<div class="form-group">
#Html.LabelFor(model => model.CategoryName, new {#class = "control-label col-md-4"})
<div class="col-md-8">
#Html.EditorFor(model => model.CategoryName, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.CategoryName, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CategoryDescription, new {#class = "control-label col-md-4"})
<div class="col-md-8">
#Html.EditorFor(model => model.CategoryDescription, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.CategoryDescription, "", new {#class = "text-danger"})
</div>
</div>
<div class="modal-footer" style="padding-right: 0px;">
<input class="btn btn-success" type="submit" value="Save"/>
<button class="btn btn-default" type="button" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
}
#Scripts.Render("~/bundles/jqueryval")
_Edit.cshtml
#model MvcPPT.ViewModels.LandTypeCategoryCreateViewModels
<div class="modal-header" style="background-color: #3498db; color: #fff;">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Add New Category Type</h4>
</div>
#using (Html.BeginForm())
{
<div class="modal-body">
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
<div class="form-group">
#Html.LabelFor(model => model.CategoryName, new {#class = "control-label col-md-4"})
<div class="col-md-8">
#Html.EditorFor(model => model.CategoryName, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.CategoryName, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CategoryDescription, new {#class = "control-label col-md-4"})
<div class="col-md-8">
#Html.EditorFor(model => model.CategoryDescription, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.CategoryDescription, "", new {#class = "text-danger"})
</div>
</div>
<div class="modal-footer" style="padding-right: 0px;">
<input class="btn btn-success" type="submit" value="Save"/>
<button class="btn btn-default" type="button" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
}
#Scripts.Render("~/bundles/jqueryval")
jQuery How Modal Call:
// Add new
$.ajaxSetup({ cache: false });
$("a[data-modal]").on("click",
function (e) {
$("#myModalContent").load(this.href,
function () {
$("#myModal").modal({
keyboard: true
},
"show");
bindForm(this);
});
return false;
});
function bindForm(dialog) {
$("form", dialog).submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$("#myModal").modal("hide");
window.location.reload();
} else {
$("#myModalContent").html(result);
bindForm(dialog);
}
}
});
return false;
});
}

since both create and edit forms are partial views which i am guessing will render on same Main view i will advice you to remove the
#Scripts.Render("~/bundles/jqueryval")
from both partial pages and add the line in the top of main page since when you click the create button it will load the script bundle and again when you click the edit it will load them for the 2nd time
next is properly write the #gtml.begin form tags like
#using (Html.BeginForm(ActionName , ControllerName, FormMethod.Post))
i am not sure how is your form post is workng now

Option 1:
You can disable the button once it is submitted then.
$('form').submit(function() {
$(this).find(':submit').attr('disabled', 'disabled');
});
Option 2:
By creating a action filter. (So here you can validate duplication of anti-forgery token.)
How do I prevent multiple form submission in .NET MVC without using Javascript?

Related

Pass id of parent view to child view and use it in controller - ASP.NET MVC 5

I am having a problem sending parent ID to child ID, even if I do, I want to display the child's data only of a particular parent. In my code, List is the parent, and Notes are the children. When I create a List, I have redirected to Notes Index Page (Different Controller) along with ID but in all lists, I can see the same notes. I am using TempData in NotesController to keep hold of that ID.
List Controller:
//Index
public ActionResult Index()
{
return View(db.Lists.ToList());
}
//Create
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ListViewModel lists)
{
if (ModelState.IsValid)
{
Lists list = new Lists();
list.CreationDate = DateTime.Now;
list.ListName = lists.ListName;
db.Lists.Add(list);
db.SaveChanges();
int? idFromView = list.Id;
return RedirectToAction("Index", "NotesInLists", new { id = idFromView });
}
return View(lists);
}
Notes Controller:
//Index
public ActionResult Index(int? id)
{
TempData["idFromView"] = id;
return View(db.NotesInLists.ToList());
}
//Create
public ActionResult CreateWithtext()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateWithtext(NoteTagViewModel notesInList)
{
if (ModelState.IsValid)
{
List<string> TagsList = notesInList.TagsList.Split(',').ToList();
NotesInList note = new NotesInList();
int tempDataId = (int)TempData["idFromView"];
note.CreationDate = DateTime.Now;
note.ListName = notesInList.ListName;
note.TextDescription = notesInList.TextDescription;
note.listID = tempDataId;
db.NotesInLists.Add(note);
db.SaveChanges();
//saving tags
foreach (var item in TagsList)
{
Tags tag = new Tags();
tag.CreationDate = DateTime.Now;
tag.TagName = item;
tag.Note_Id = note.Id;
db.Tags.Add(tag);
}
db.SaveChanges();
return RedirectToAction("Index", new { id = tempDataId });
}
return View(notesInList);
}
Here, in this NotesController, I am also saving tags and it is working fine, but the main issue is with List. Also using ViewModels but that is of no concern to me for now. If I try accessing List using
Lists list = new List();
I still am not able to check and compare that ID with that List ID, it throws an exception.
List Model:
namespace NoteBlocks.Models
{
public class Lists
{
public int Id { get; set; }
[Required]
[Display(Name = "List Name")]
public string ListName { get; set; }
[Display(Name = "Creation Date")]
public DateTime? CreationDate { get; set; }
[Display(Name = "Last Updated")]
public DateTime? UpdateDate { get; set; }
}
}
List ViewModel:
namespace NoteBlocks.ViewModels
{
public class ListViewModel
{
public int Id { get; set; }
[Required]
[Display(Name = "List Name")]
public string ListName { get; set; }
[Display(Name = "Creation Date")]
public DateTime? CreationDate { get; set; }
[Display(Name = "Last Updated")]
public DateTime? UpdateDate { get; set; }
}
}
Notes Model:
namespace NoteBlocks.Models
{
public class NotesInList
{
public int Id { get; set; }
[Required]
[Display(Name = "List Name")]
public string ListName { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Creation Date")]
public DateTime? CreationDate { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Last Updated")]
public DateTime? UpdateDate { get; set; }
public string customFile { get; set; }
[Display(Name = "Enter Note Content")]
public string TextDescription { get; set; }
public Lists List { get; set; }
public int listID { get; set; }
}
}
Notes ViewModel:
namespace NoteBlocks.Models
{
public class NoteTagViewModel
{
public int NoteId { get; set; }
[Required]
[Display(Name = "List Name")]
public string ListName { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Creation Date")]
public DateTime? CreationDate { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Last Updated")]
public DateTime? UpdateDate { get; set; }
public string customFile { get; set; }
[Display(Name = "Enter Note Content")]
public string TextDescription { get; set; }
//multiple tags
public string TagsList { get; set; }
public Lists List { get; set; }
public int ListId { get; set; }
}
}
Created a foreign key but it is not working.
HTML - List Index
#model IEnumerable<NoteBlocks.Models.Lists>
#{
ViewBag.Title = "List";
//ViewBag.Id = model.Lists.Id;
}
<h2>List</h2>
<p>
#Html.ActionLink(" Create New List", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ListName)
</th>
<th>
#Html.DisplayNameFor(model => model.CreationDate)
</th>
<th>
#Html.DisplayNameFor(model => model.UpdateDate)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
//using ActionLink to open list of notes for that particular List
//and passing particular List ID from here if already created
#Html.ActionLink(item.ListName, "Index", "NotesInLists", new { id = item.Id }, null)
#*#TempData.Peek("tempDataId")*#
</td>
<td>
#Html.DisplayFor(modelItem => item.CreationDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.UpdateDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
#Html.ActionLink("Details", "Details", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
HTML - List Create
#model NoteBlocks.Models.Lists
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>List</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.ListName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ListName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ListName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CreationDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CreationDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CreationDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UpdateDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UpdateDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.UpdateDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
HTML - Notes Index
#model IEnumerable<NoteBlocks.Models.NotesInList>
#{
ViewBag.Title = "List Notes";
}
<h2>List Notes</h2>
<p id="buttonsInPTag">
<button type="button" class="btn btn-primary" id="addButton1"><span class="glyphicon glyphicon-plus">#Html.ActionLink(" Create Textual Note", "CreateWithtext")</span></button>
<button type="button" class="btn btn-primary" id="addButton2"><span class="glyphicon glyphicon-plus">#Html.ActionLink(" Create Note from Document", "CreateWithDoc")</span></button>
<button type="button" class="btn btn-primary" id="addButton3"><span class="glyphicon glyphicon-plus">#Html.ActionLink(" Create Image Note", "CreateWithImage")</span></button>
<button type="button" class="btn btn-primary" id="addButton4"><span class="glyphicon glyphicon-plus">#Html.ActionLink(" Create Audio / Video Note", "CreateWithMedia")</span></button>
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ListName)
</th>
<th>
#Html.DisplayNameFor(model => model.CreationDate)
</th>
<th>
#Html.DisplayNameFor(model => model.UpdateDate)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ListName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreationDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.UpdateDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("Details", "Details", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</table>
HTML - Notes CreateWithText
#model NoteBlocks.Models.NoteTagViewModel
#{
ViewBag.Title = "Create Note with Text";
}
<h2>Create Note with Text</h2>
#using (Html.BeginForm("CreateWithText", "NotesInLists", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.ListName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ListName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ListName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TextDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<textarea cols="50" rows="12" class=form-control id="TextDescription" name="TextDescription"></textarea>
#Html.ValidationMessageFor(model => model.TextDescription, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.Label("Tags", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" id="tagsField" name="tagsField" class=form-control data-role="tagsinput" />
<input type="hidden" name="TagsList" id="TagsList" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section scripts
{
<script>
$(document.body).on('focusout', '.bootstrap-tagsinput input', () => {
let array = $('#tagsField').tagsinput('items');
$("#TagsList").val(array);
})
</script>
}
I am stuck to this point. Please guide. p.s. using code first approach.
There is no filter applied to the query that gets notes in your Index action of notes controller.
I think adding where method;
.Where(x=>x.listID == id)
will solve your problem.
//Index
public ActionResult Index(int? id)
{
TempData["idFromView"] = id;
return View(db.NotesInLists/*.Where(x=>x.listID == id)*/.ToList());
}

Scaffolded create View returns System.Web.Mvc.WebViewPage<TModel>.Model.get returned null. before post

I have a scaffolded "create" view that, when I ty to create a new record, returns the error: System.Web.Mvc.WebViewPage<TModel>.Model.get returned null. Even before I pressed "save".
My model:
namespace Itucation.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("jobcoach")]
public partial class jobcoach
{
public int kursist_id { get; set; }
//[Column(TypeName = "text")]
public string note { get; set; }
[Key]
public int jobcoach_note_id { get; set; }
[Column("status")]
//[StringLength(50)]
[Display(Name = "Status")]
public string status { get; set; }
[Column(TypeName = "date")]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Success dato")]
public DateTime? succesDato { get; set; }
public int? AntalSamtaler { get; set; }
public virtual kursister kursister { get; set; }
}
}
My controller:
// GET: jobcoach/Create
public ActionResult Create(int? id)
{
ViewBag.kursist_id = new SelectList(db.kursister, "kursist_id", "fornavn");
ViewBag.status = new SelectList(db.JobcoachStatus, "status", "status");
ViewBag.ID = id;
ViewBag.kursist = (from k in db.kursister
where k.kursist_id == id
select k);
//var jc = db.jobcoach.Where(u => u.kursist_id == id).ToList().FirstOrDefault();
var jc = db.jobcoach.Where(r => r.kursist_id == id).ToList().FirstOrDefault();
if (jc == null)
{
// param is not set
}
else
{
return RedirectToAction("Edit/" + jc.jobcoach_note_id);
}
return View();
}
// POST: jobcoach/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "jobcoach_note_id,kursist_id,note,status,succesDato, AntalSamtaler")] jobcoach jobcoach)
{
if (ModelState.IsValid)
{
//Brugernavn (current user) skal også indsættes
jobcoach.note = jobcoach.note + " Af " + User.Identity.Name + " - " + DateTime.Now.ToString();
db.jobcoach.Add(jobcoach);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.kursist_id = new SelectList(db.kursister, "kursist_id", "fornavn", jobcoach.kursist_id);
return View(jobcoach);
}
My View:
#model Itucation.Models.jobcoach
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div>
<h4>jobcoach</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div>
#Html.LabelFor(model => model.kursist_id, "Kursist", htmlAttributes: new { #class = "control-label " })
<div>
#{
foreach (var navn in (ViewBag.kursist))
{
<text>Kursist ID: </text>#navn.kursist_id <br />
<text>Navn:</text> #navn.fornavn<text> </text> #navn.efternavn <br />
<text>E-mail: </text>#navn.mail
}
}
<input type="hidden" name="kursist_id" id="kursist_id" value="#ViewBag.ID" />
#*#Html.DropDownList("kursist_id", null, htmlAttributes: new { #class = "form-control" })*#
#Html.ValidationMessageFor(model => model.kursist_id, "", new { #class = "text-danger" })
</div>
</div>
<div>
#Html.LabelFor(model => model.note, htmlAttributes: new { #class = "control-label " })
<div>
#Html.TextAreaFor(model => model.note, new { #class = "form-control", #cols = "100%", #rows = "20", #tabindex = "21" })
#Html.ValidationMessageFor(model => model.note, "", new { #class = "text-danger" })
</div>
</div>
<div>
Status
<div>
<select id="status">
<option value="Uden status">Uden status </option>
<option value="Ordinær uddannelse">Ordinær uddannelse</option>
<option value="Deltidsjob">Deltidsjob</option>
<option value="Praktik">Praktik</option>
<option value="Løntilskud privat">Løntilskud privat</option>
<option value="Løntilskud offentlig">Løntilskud offentlig</option>
<option value="Ordinært job">Ordinært job</option>
</select>
</div>
</div>
<div>
Success dato
<div>
<input type="date" id="succesDato" name="succesDato" />
</div>
</div>
<div>
Antal samtaler
<div>
<input type="text" id="AntalSamtaler" name="AntalSamtaler" value="#Model.AntalSamtaler"/>
</div>
</div>
#*<div>
#Html.LabelFor(model => model.status, htmlAttributes: new { #class = "control-label " })
<div>
<select id="status" name="status" class="form-control ">
<option>Vælg evt. en status</option>
<option value="Ordinært job">Ordinært job</option>
<option value="Ordinær uddannelse">Ordinær uddannelse</option>
<option value="Deltidsjob">Deltidsjob</option>
<option value="Praktik">Praktik</option>
<option value="Løntilskud privat">Løntilskud privat</option>
<option value="Løntilskud offentlig">Løntilskud offentlig</option>
</select>
</div>
</div>*#
<div class="form-group col-md-12">
<div class="col-md-offset-2 col-md-1">
<input type="submit" value="Opret" class="btn btn-default" />
</div>
</div>
</div>
}
<div class="col-md-10">
#Html.ActionLink("Tilbage til listen", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I would expect an "empty" view whith all the input fields, where I could input the date and the hit "save". Instead I get the error.
The error occurs at the line: #Html.ValidationMessageFor(model => model.note, "", new { #class = "text-danger" }).
I cannot seem to figure this out. I see many questions that refer to this error, but none seem to be applicable to my problem.
I would be very gratefull for any help.
This is because you're using a binding between the view and the model of type jobcoach. In the view if you want to bind the view to a model, you must pass it as a parameter at the View() method of controller, in this way:
jobcoach jc=new jobcoach();
return View(jc);
What you're trying to do now, is to render the create view from a "null" model, because you're using the #Html model-typed method helpers (LabelFor, ValidationMessageFor....)
So, when it tries to bind the view with the model, the error throws, because it hasn't the Model proerty setted into the view.
I found the problem: I was trying to acces #Model.AntalSamtaler, but that was null, since I hadn't saved it yet. I changed the line:
<input type="text" id="AntalSamtaler" name="AntalSamtaler" value="#Model.AntalSamtaler"/>
to:
<input type="text" id="AntalSamtaler" name="AntalSamtaler" value="1"/>
I made this mistake by copy/pasting from the "edit" view, where #Model.AntalSamtaler was set.

How can I set a validationmessage for inputfield binded to entitymodel?

How can i set a validation message on all of these fields? Im not sure how to set it when I bind everything directly to my entitymodel Cancellation? I tried setting a validationmessage directly in my entityclass nut no luck.
This is my razorpage
#page
#model Index
#{
ViewBag.Title = "Index";
}
<div class="body-content">
<form id="avboka-form" method="post">
#Html.AntiForgeryToken()
<div class="form-group">
<div class="col-med-5">
<label asp-for="Cancellation.Elev"></label>
<input type="text" id="elev" asp-for="Cancellation.Elev" class="form-control">
<span asp-validation-for="Cancellation.Elev"></span>
</div>
</div>
<div class="form-group">
<div class="col-med-5">
<label asp-for="Cancellation.Dag"></label>
<input asp-for="Cancellation.Dag" type="datetime" id="datepicker" class="datepicker1 form-control">
<span asp-validation-for="Cancellation.Dag"></span>
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => Model.SelectedKommun, htmlAttributes: new { #class = "control-label col-med-2" })
<div class="col-med-5">
#Html.DropDownListFor(x => Model.Cancellation.KommunId, new SelectList(Model.Kommun, "Value", "Text"), htmlAttributes: new { #class = "form-control", id = "kommun" })
#Html.ValidationMessageFor(x => x.SelectedKommun, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => Model.SelectedFordon, htmlAttributes: new { #class = "control-label col-med-2" })
<div class="col-med-5">
#Html.DropDownListFor(x => Model.Cancellation.FordonId, new SelectList(Model.Fordon, "Value", "Text"), htmlAttributes: new { #class = "form-control", #id = "fordon" })
#Html.ValidationMessageFor(x => x.SelectedFordon, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-med-5">
<label asp-for="Cancellation.Skola.Namn"></label>
<select id="skola" name="Cancellation.SkolaId" class="form-control">
#foreach (var schools in Model.School)
{
<option value="#schools.Id">#schools.Namn</option>
}
</select>
<span asp-validation-for="Cancellation.SkolaId"></span>
</div>
<input type="submit" name="save" value="Avboka skolskjuts" class="vt-btn" />
</form>
</div>
Here is part of my pagemodel where i bind my input-fields. The selects is collected from other tables and therefore is never empty.
[BindProperty]
public Avbokning Cancellation { get; set; }
public Index(SqlAvbokningData<Avbokning> avbokningRepo, SqlKommunData<Kommun> kommunRepo, SqlFordonData<Fordon> fordonRepo, SqlSkolaData<Skola> skolaRepo)
{
_avbokningRepo = avbokningRepo;
_kommunRepo = kommunRepo;
_fordonRepo = fordonRepo;
_skolaRepo = skolaRepo;
}
public async Task<IActionResult> OnGet()
{
Kommun = await _kommunRepo.GetKommuner();
Fordon = _fordonRepo.GetFordon();
Municipalities = await _kommunRepo.GetAll();
Vehicle = await _fordonRepo.GetAll();
School = await _skolaRepo.GetAll();
return Page();
}
[ValidateAntiForgeryToken]
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
//if (!Cancellation.Validate())
// return Redirect("/");
await _avbokningRepo.Add(Cancellation);
return Redirect("/Tack");
}
return RedirectToAction("OnGet");
}
Validation in MVC can be done with a viewmodel. You specify your model this way:
public class LogOnViewModel
{
[Required(ErrorMessage = "RequiredField")]
[Display(Name = "Username")]
public string Username { get; set; }
[Required(ErrorMessage = "RequiredField")]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
}
Once you get to the web page itself, the ValidationMessageFor will then validate the fields based on the data annotations you have placed on your viewmodel, as you pass that on to the web page.
In the controller you can pass it on to the page by means like this:
var viewModel = new LogOnViewModel();
// do stuff
return View(viewModel);
It's not a perfect example, but this should give some idea of how you can use it.

How to send model from parent to child

I have question about how to send model from parent to child using partial view and fancybox.
Here is my model
public class SampleHeaderViewModels
{
[Display(Name = "ID")]
public int intID { get; set; }
[Display(Name = "Field 1")]
public string txtField1 { get; set; }
[Display(Name = "Field 2")]
public string txtField2 { get; set; }
}
public class SampleDetailViewModels
{
[Display(Name = "ID")]
public int intID { get; set; }
[Display(Name = "Line")]
public int intLine { get; set; }
[Display(Name = "Detail 1")]
public string txtDetail1 { get; set; }
}
public class SampleViewModels
{
public SampleHeaderViewModels Header { get; set; }
public List<SampleDetailViewModels> Detail { get; set; }
public SampleDetailViewModels OneDetai { get; set; }
public SampleViewModels()
{
Header = new SampleHeaderViewModels();
Detail = new List<SampleDetailViewModels>();
OneDetai = new SampleDetailViewModels();
}
}
Here is my Index View:
<div class="row">
<div class="block">
<div class="block-content controls">
<div class="col-md-6">
<div class="row-form">
<div class="col-md-4">
#Html.LabelFor(m => m.Header.txtField1, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.HiddenFor(m => m.Header.intID)
#Html.TextBoxFor(m => m.Header.txtField1, htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="row-form">
<div class="col-md-4">
#Html.LabelFor(m => m.Header.txtField2, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.TextBoxFor(m => m.Header.txtField2, htmlAttributes: new { #class = "form-control" })
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="block">
<div class="block-content controls">
<div class="col-md-12">
<div class="row-form">
<table id="tbDataTable" class="table table-bordered">
<thead>
<tr>
<td>
#Html.LabelFor(m => m.Detail.FirstOrDefault().intLine)
</td>
<td>
#Html.LabelFor(m => m.Detail.FirstOrDefault().txtDetail1)
</td>
</tr>
</thead>
<tbody>
#if (Model.Detail != null)
{
foreach (var item in Model.Detail)
{
<tr>
<td>
#Html.DisplayFor(m => item.intLine)
</td>
<td>
#Html.DisplayFor(m => item.txtDetail1)
</td>
</tr>
}
}
</table>
</div>
<div class="row-form">
<div class="col-md-2">
<button type="button" id="btnAddDetail" class="btn btn-info">Add Detail</button>
</div>
</div>
</div>
</div>
</div>
</div>
And my Index Have javascript:
<script>
$("#btnAddDetail").click(function () {
debugger;
var model = #Html.Raw(Json.Encode(Model));
$.ajax({
type: 'POST',
contentType: 'application/json',
url: '/Sample/ViewDetail',
//data: $('#form1').serialize(),
data: JSON.stringify(model),
contentType: "application/json; charset=utf-8",
datatype: 'JSON',
success: function (data) {
// on success, post returned data in fancybox
$.fancybox.open(data,
{
closeClickOutside: false,
iframe: {
preload: true
}
}
); // fancybox
},
error: function (data) {
console.log(data);
}
});
});
</script>
Here is my Partial View:
<div class="col-md-6">
<div class="row-form">
<div class="col-md-4">
#Html.LabelFor(m => m.OneDetai.intLine, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.TextBoxFor(m => m.OneDetai.intLine, htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="row-form">
<div class="col-md-4">
#Html.LabelFor(m => m.OneDetai.txtDetail1, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.TextBoxFor(m => m.OneDetai.txtDetail1, htmlAttributes: new { #class = "form-control" })
</div>
</div>
</div>
<div class="row-form">
<div class="col-md-2">
<button type="submit" id="btnAddLine" class="btn btn-info">Add Detail</button>
</div>
</div>
And this is my Controller
public ActionResult Index()
{
return View(new SampleViewModels());
}
[HttpPost]
public ActionResult ViewDetail(SampleViewModels obj)
{
return PartialView("AddDetail", obj);
}
public ActionResult AddDetail(SampleViewModels obj)
{
obj.Detail.Add(obj.OneDetail);
return View("Index", obj);
}
The idea is: In order to add new detail, I have to click btnAddDetail. And it will open popup. I have to fill the popup and click btnAddLine in child form. And the data will be appear in datatable.
The question is, how I can send my Parent Model to Child model using ajax?
When the button btnAddDetail in Index triggered, I tried to send my model in JSON, but its always send the FIRST STATE of my model. If I set value in Field 1 and Field 2, and press btnAddDetail, my ViewDetail Controller always get null model. Field1 = null, Field2 = null.
I've tried data: $('#form1').serialize(), to send my Model, It won't send my Detail Model. It just send my Header model.
Is there any way to send my Model to partial view, and send it back to my parent view?
Please help me, I haven't find any solution yet.
Thank you.
var model = #Html.Raw(Json.Encode(Model));
will not work, you will always get null...
if you have to make ajax post, you should do this to get values
for textbox values give them id and set your json
var model = {
"Header": {
"intID": 0,
"txtField1": $("#id-textField1").val(),
"txtField2": $("#id-textField2").val(),
},
"Detail": [],
"OneDetai": {
"intID": 0,
"intLine": 0,
"txtDetail1": null
}
}

ASP.NET MVC4 IEnumerable empty on post

I have read several answers on this issue but despite this, it would appear I have developed code blindness.
I have the following view model:
public class IndividualProductVm
{
public virtual Products Products { get; set; }
public ProductSummary ProductSummary { get; set; }
public virtual IEnumerable<ProductSimpleResponse> ProductSimpleResponse { get; set; }
}
This is then passed into a view and then a partial view:
#model Websites.ViewModels.IndividualProductVm #{ ViewBag.Title = "Edit"; }
<h2>Edit</h2>
#using (Html.BeginForm(null, null, FormMethod.Post, new { name = "form", id = "mainForm" })) { #Html.AntiForgeryToken() #Html.ValidationSummary(true, "", new { #class = "text-danger" }) #Html.HiddenFor(model => model.Products.Id) #Html.HiddenFor(model
=> model.ProductSummary.SupplierId) Html.RenderPartial("_IndividualProduct", Model);
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index", new { id = Model.ProductSummary.SupplierId }, new { #class = "btn btn-default" })
</div>
#section Scripts { #Scripts.Render("~/bundles/jqueryval") }
#model Websites.ViewModels.IndividualProductVm
<div>
#Html.LabelFor(model => model.Products.ProductCode, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.DisplayFor(model => model.Products.ProductCode, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div style="clear:both;"></div>
<div>
#Html.LabelFor(model => model.Products.ProductDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.DisplayFor(model => model.Products.ProductDescription, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<table class="table">
<tr>
<th>
Present
</th>
</tr>
#foreach (var item in Model.ProductSimpleResponse)
{
<tr>
#Html.HiddenFor(modelItem => item.Id)
#Html.HiddenFor(modelItem => item.SupplierId)
#Html.HiddenFor(modelItem => item.ProductCode)
<td>
#Html.EditorFor(modelItem => item.Present)
</td>
</tr>
}
</table>
However, when I enter the edit post, my viewmodel is null for the IEnumerable<ProductSimpleResponse> but fine for the other two classes.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(IndividualProductVm model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index", new { id = model.ProductSummary.SupplierId });
}
return View(model.Products);
}
If someone can explain what I'm doing wrong, I'd be most grateful.
Your property name is ProductSimpleResponse, alhtough the type is ProductSvhcSimpleResponse, so to iterate through it you should have.
#foreach (var item in Model.ProductSimpleResponse)
NOT
#foreach (var item in Model.ProductSvhcSimpleResponse)
use List because
IEnumerable is suitable just for iterate through collection and you can not modify (Add or Remove) data IEnumerable bring ALL data from server to client then filter them, assume that you have a lot of records so IEnumerable puts overhead on your memory.
public class IndividualProductVm
{
public virtual Products Products { get; set; }
public ProductSummary ProductSummary { get; set; }
public virtual List<ProductSvhcSimpleResponse> ProductSimpleResponse { get; set; }
}
More help click here

Categories

Resources