I have two date values, that I need to validate. This validaton is compound: One date needs to be sooner than the other (think StartingDate and FinishDate).
How can I validate for this?
Based on this post, which seems to pose a similar situation, one recomendation is to use MVC Foolproof Validation. Is this still the best option? Is there other way to validate such task?
My code in the view, if it helps:
<div class="row">
<div class="col-md-3">
<div class="row">
<div class="col-md-5">
<span class="glyphicon glyphicon-calendar" aria-hidden="true"></span>
<span style="font-size:large;">Início </span>
</div>
<div class="col-md-7">
#Html.EditorFor(model => model.Inicio, new { htmlAttributes = new { #class = "form-control datetimepicker" } })
</div>
</div>
</div>
<div class="col-md-3">
<div class="row">
<div class="col-md-5">
<span class="glyphicon glyphicon-calendar" aria-hidden="true"></span>
<span style="font-size:large;">Fim </span>
</div>
<div class="col-md-7">
#Html.EditorFor(model => model.Fim, new { htmlAttributes = new { #class = "form-control datetimepicker" } })
</div>
</div>
</div>
</div>
<script>
<!--jQuery DateTimePicker-->
jQuery('.datetimepicker').datetimepicker({
format: 'd/m/Y H:i'
});
</script>
I don't see why a simple JS solution can't help here, so here it is:
HTML:
<p>Start Date: <input type="text" id="datepicker1"></p>
<p>End Date: <input type="text" id="datepicker2"></p>
<button id="TestCondition">
Click Me!
</button>
JS:
$(function() {
$("#datepicker1").datepicker();
});
$(function() {
$("#datepicker2").datepicker();
});
$("#TestCondition").click(function(){
alert($("#datepicker1").val());
alert($("#datepicker2").val());
if($("#datepicker2").val() < $("#datepicker1").val()){
alert("End Date must come after Start Date!");
}
});
Here is a fiddle for that: JSFiddle
Alternate Solution using Controller in MVC
Once you submit this page to the controller, you can do a check like so (C#):
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult NameOfAction(ViewModel nameOfViewModel)
{
if(nameofViewModel.FinishDate <= nameofViewModel.StartDate)
{
ModelState.AddModelError("FinishDate", "Finish Date needs to be after the Start Date!");
return View(nameOfViewModel);
}
}
Let me know if this helps, or if anything needs to be changed.
Based on BviLLe_Kid answer, which I accept, here's what I ended up doing:
if (ModelState.IsValid)
{
if (nameofViewModel.FinishDate <= nameofViewModel.StartDate)
{
ModelState.AddModelError(string.Empty, "Error message here");
return View(nameofViewModel);
}
else {
//code for when validation is OK
}
}
In the view:
<div style="color:red;">
#Html.ValidationSummary(true)
#Html.ValidationMessageFor(model => model.FinishDate)
</div>
Related
I am making a searchfield which triggers a request function returning partial view and according to result I want to show the response in partial view under the searchfield in the same page. User writes something to textfield and clicks the search button then under them result shows. I get the result but my partialview is opening in another page instead of under the searchfield in the same page. Also looks like my onClick function does not trigger.
My main View:
<div class="container">
<!-- Outer Row -->
<div class="row justify-content-center">
<div class="col-6 p-3">
<form class="form-group" method="post" action="/Books/BookDetail">
<div class="input-group">
<input type="text" name="barcodes" class="form-control bg-light border-0 small bg-gray-200" placeholder="Kitap Barkodunu giriniz..." aria-label="Search" aria-describedby="basic-addon2">
<button class="btn btn-primary" type="submit" id="myBtn" name="myBtn" onclick="showBook">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</form>
</div>
<br />
<div id="partialContent">
</div>
</div>
</div>
<script>
function showBook() {
$('#partialContent').load("/Controllers/BooksController/BookDetail");
}
</script>
Book Detail Controller:
public IActionResult BookDetail(string barcodes)
{
var request = $"?barcodes={barcodes}";
var products = _httpTool.HttpGetAsync<List<Products>>($"{AppSettings.ApiUrl}/GetProducts{request}");
if(products.Result.Count != 0)
{
ViewBag.result = "Success";
var product = products.Result[0];
return PartialView("_BookDetailPartial", product);
}
else
{
ViewBag.result = "Failed";
return View("AddBook");
}
}
_BookDetailPartial:
<div>
<h4>PartialCame</h4>
<br />
<h5>#Model.Author</h5>
</div>
What is the problem here?
Thanks in advance!
onclick="showBook"
should be
onclick="showBook()"
And this path appears to be wrong: "/Controllers/BooksController/BookDetail" it should most likely be "/Books/BookDetail?barcodes=barcode"
I'm not sure what you mean about the partial view loading in another page. Could you give some more detail please?
How do I get the get method called aidx parameter by post method?
When I start with the current code, it says that it is not defined.
aidx is the primary key, and I want to assign that primary key to the Family column.
<div id="blogpost" class="inner-content">
<form id="formdata"action="#Url.Action("Detail", "Board")" method="post" enctype="multipart/form-data">
<section class="inner-section">
<div class="main_blog text-center roomy-100">
<div class="col-sm-8 col-sm-offset-2">
<div class="head_title text-center">
<h2>#Html.DisplayTextFor(m => m.Article.Title)</h2>
#Html.HiddenFor(m => m.Article.ArticleIDX)
<div class="separator_auto"></div>
<div class="row">
<div class="col-md-8" style="margin-left:6%;">
<p>
<label>분 류 : </label>
#Html.DisplayTextFor(m => m.Article.Category)
</p>
</div>
<div class="col-md-8" style="margin-left:5%;">
<p>
<label>작성자 : </label>
#Html.DisplayTextFor(m => m.Article.Members.Name)
</p>
</div>
<div class="col-md-8" style="margin-left:10.6%;">
<p>
<label>작성일 : </label>
#Html.DisplayTextFor(m => m.Article.ModifyDate)
</p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
<label style="font-size:x-large;">문의내용</label>
<br />
<br />
#Html.DisplayTextFor(m => m.Article.Contents)
<br />
<br />
<br />
<br />
</p>
</div>
</div>
<div class="dividewhite2"></div>
<p>
#if (User.Identity.IsAuthenticated == true)
{
<button type="button" class="btn btn-sm btn-lgr-str" onclick="btnEdit()">수정하기</button>
<button type="button" class="btn btn-sm btn-lgr-str" onclick="btnReply()">답글달기</button>
}
<button type="button" class="btn btn-sm btn-lgr-str" onclick="javascript:history.go(-1);">목록이동</button>
<br />
<br />
<br />
<br />
</p>
<div>
#Html.Partial("_Comment", new ViewDataDictionary { { "id", Model.Article.ArticleIDX } })
#Html.Partial("_CommentView", new ViewDataDictionary { { "CommentIDX", ViewBag.CommentIDX }, { "idx", Model.Article.ArticleIDX } })
</div>
</div>
</div>
<div class="dividewhite8"></div>
</section>
</form>
<script >
function btnEdit() {
if (#User.Identity.Name.Equals(Model.Article.Members.ID).ToString().ToLower() == true)
{
location.replace("/Board/Edit?aidx=#Model.Article.ArticleIDX");
}
else
{
alert("권한이 없습니다.");
}
}
function btnReply() {
location.replace("ReplyCreate?aidx=#Model.Article.ArticleIDX");
}
[HttpGet]
public ActionResult ReplyCreate(int aidx)
{
Articles articleReply = new Articles();
return View(articleReply);
}
[HttpPost]
public ActionResult ReplyCreate(Articles replyArticles, int aidx)
{
try
{
replyArticles.Family = aidx;
replyArticles.ModifyDate = DateTime.Now;
replyArticles.ModifyMemberID = User.Identity.Name;
db.Articles.Add(replyArticles);
db.SaveChanges();
ViewBag.Result = "OK";
}
catch (Exception ex)
{
ViewBag.Result = "FAIL";
}
return View(replyArticles);
}
You have several problem in your HTML and JavaScript:
You're not submitting anything, you're redirecting the page in JavaScript.
You're hiding the button if the user is not authenticated, but everybody can see, copy, and run the URL from your JavaScript.
Even if you fix #1 and your ReplyCreate() action gets called, it's expecting 2 parameters, but you're only sending one (aidx). The other parameter (replyArticles) will be always null.
Your code is vulnerable to CSRF attack.
To fix #1, you can add the parameter to your form instead of JavaScript, and change your button's type to submit:
<form id="formdata"
action="#Url.Action("Detail", "Board", null, new { aidx = Model.Article.ArticleIDX })"
method="post" enctype="multipart/form-data">
<div class="dividewhite2"></div>
<p><button type="submit" class="btn btn-sm btn-lgr-str">답글달기</button></p>
</form>
Or you can use a hidden field.
To fix #2, move the check outside the form and delete your JavaScript:
#if (User.Identity.IsAuthenticated) {
<form id="formdata"
action="#Url.Action("Detail", "Board", null, new { aidx = Model.Article.ArticleIDX })"
method="post" enctype="multipart/form-data">
<div class="dividewhite2"></div>
<p><button type="submit" class="btn btn-sm btn-lgr-str">답글달기</button></p>
</form>
}
To fix #3, you'll have to add the replyArticles parameter to your form or as a hidden field.
To fix #4, you'll need to add the forgery check to your form and your action.
Layout -> View -> Partial View
In the View:
<div class="col-md-8">
#{Html.RenderPartial("_komentari", commentlist);}
<div class="gap gap-small"></div>
<div class="box bg-gray">
<h3>#Res.commentwrite_title</h3>
#using (Ajax.BeginForm("postcomment", new { propertyid = Model.PublicID }, new AjaxOptions { UpdateTargetId = "commentsarea", HttpMethod = "Post", InsertionMode = InsertionMode.Replace }, null))
{
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label>#Res.commentwrite_content</label>
<textarea id="comment" name="comment" class="form-control" rows="6"></textarea>
</div>
<div class="form-group">
<input class="btn btn-primary" type="submit" value='#Res.commentwrite_btn' />
</div>
</div>
</div>
}
</div>
</div>
In the Partial View:
<div id="commentsarea">
<ul class="booking-item-reviews list">
#if (Model != null)
{
foreach (Comment item in Model)
{
<li>
<div class="row">
<div class="col-md-2">
<div class="booking-item-review-person">
<a class="booking-item-review-person-avatar round" href="#">
<img src="/assets/img/70x70.png" alt="Image Alternative text" title="Bubbles" />
</a>
<p class="booking-item-review-person-name">
#if (item.UserId != null)
{
<a href='#Url.Action("details", "user", new { userid = item.User.PublicId })'>#item.User.Username</a>
}
else
{
Anonymous
}
</p>
</div>
</div>
<div class="col-md-10">
<div class="booking-item-review-content">
<p>
#item.Content
</p>
<p class="text-small mt20">#item.DateOnMarket</p>
<p class="booking-item-review-rate">
#using (Ajax.BeginForm("reportcomment", new { comment = item.PublicId }, new AjaxOptions { UpdateTargetId = "reportscount", HttpMethod = "Post", InsertionMode = InsertionMode.Replace }, null))
{
<a id="submit_link" href="#">Spam?</a>
<a class="fa fa-thumbs-o-down box-icon-inline round" href="#"></a>
}
<b id="reportscount" class="text-color">#item.CommentReports.Count</b>
</p>
</div>
</div>
</div>
</li>
}
}
</ul>
</div>
<script>
$(function () {
$('a#submit_link').click(function () {
$(this).closest("form").submit();
});
});
</script>
View
Both scripts for Ajax are always included in the Layout (I'm already using Ajax on other pages too). On the View page, when I add a new comment, it is added in the database and shows the updated list of comments via ajax. Everything works fine.
Partial View
But if I want to report the comment as spam, I have to click on the link inside the Partial View (#submit_link), and after reporting, inside the #reportscount part, I want to show the updated number of reports of that comment. The actionresults returns that number like Content(numberofreports.toString()). It works but I get the number in a blank page?
Thank you very much.
It's better if you don't. The main issue is that, for security reasons, <script> tags are ignored, when HTML is inserted into the DOM. Since the Ajax.* family of helpers work by inserting <script> tags in place, when you return the partial via AJAX, those will not be present. It's better if you only include the HTML contents of the form in the partial, and not the form itself.
I have a page which has a list of Students. The partial view which renders a list is called "StudentManager". The partial view which I use in a modal to create a new student is called "NewStudent".
I have a couple of issues going on with this controller code. For some reason, after I press submit on the "NewStudent" partial view, every time afterwards that I refresh the page a new student is there without me going in and pressing submit... This is a problem.
Also, I have searched similar topics here on stack and I cannot seem to understand why return PartialView("StudentManager",db.Students.ToList()); will not automatically refresh my "StudentManager" view.
This code is supposed to give me a list in one partial view, and another partial view is supposed to let me create a new list item and then tell the list partial view to update.
Controller:
public ViewResult Index()
{
return View();
}
public ActionResult StudentManager()
{
return PartialView(db.Students.ToList());
}
public ActionResult NewStudent()
{
return PartialView();
}
//
// POST:
[HttpPost]
public ActionResult NewStudent(Student student)
{
if (ModelState.IsValid)
{
db.Students.Add(student);
db.SaveChanges();
return RedirectToAction("Index");
}
return PartialView();
}
Index.cshtml:
#Html.Action("StudentManager", "StudentController")
<div class="modal modal-wide fade" id="myModal4" role="dialog">
<div class="modal-dialog">
#Html.Action("NewStudent", "StudentController")
</div>
</div>
Here is the "NewStudent.cshtml" view:
#model GunneryTracker.Models.Student
<fieldset>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<center>
<h4 class="modal-title">New Student</h4>
</center>
</div>
<div class="modal-body">
<div class="col-md-12">
<div class="clearfix"></div>
<div class="x_content">
<br />
<form class="form-horizontal form-label-left" >
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12">
<label class="control-label col-md-2 col-sm-2 col-xs-12" style="margin-right:10px">Course</label>
<div class="col-md-3 col-sm-3 col-xs-12">
#Html.DropDownList("CourseID", null, "-- Select Course --", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CourseID, "", new { #class = "text-danger" })
</div>
<label class="control-label col-md-2 col-sm-2 col-xs-12" style="margin-right:10px">Location</label>
<div class="col-md-3 col-sm-3 col-xs-12">
#Html.DropDownList("LocationID", null, "-- Select Location--", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.LocationID, "", new { #class = "text-danger" })
</div>
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FName)
#Html.ValidationMessageFor(model => model.FName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LName)
#Html.ValidationMessageFor(model => model.LName)
</div>
</div>
<br />
<br />
<div class="form-group">
<center>
<p>
<input type="submit" value="Create" />
</p>
</center>
</div>
</form>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Save</button>
</div>
</div>
</fieldset>
Pardon the slouchy html... The prettyfication isnt completed...
Answer to 2nd question(if I understood what you meant):
It's not that smart as you expected.
After POST better to send back JSON result or simple null if don't use Ajax.
I would suggest you after POST do return RedirectToAction("Index");
Then page auto refresh students list.
Or do your POST via $.ajax and on success update student list using jquery or js
here is how I'm usually do it for simple "admin page" forms.
public ActionResult Teams()
{
var list = _data.GetTeams(true);
return View(list);
}
public ActionResult TeamCreate()
{
var model = _data.GetTeamCRUDViewModel();
return PartialView("_TeamCreate",model);
}
[HttpPost]
public ActionResult TeamCreate(TeamCRUDViewModel model)
{
_data.SaveTeam(model);
return RedirectToAction("Teams");
}
But on customer UI I would recommended to use $.ajax post.
Update:
Ok I see your issue
#model Student
<fieldset>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">× </button>
<center>
<h4 class="modal-title">New Student</h4>
</center>
</div>
<div class="modal-body">
<div class="col-md-12">
<div class="clearfix"></div>
<div class="x_content">
<br />
#using (#Html.BeginForm("NewStudent", "Home", FormMethod.Post))
{
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12">
<label class="control-label col-md-2 col-sm-2 col-xs-12" style="margin-right: 10px">Course</label>
<div class="col-md-3 col-sm-3 col-xs-12">
#Html.DropDownList("CourseID", null, "-- Select Course --", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CourseID, "", new { #class = "text-danger" })
</div>
<label class="control-label col-md-2 col-sm-2 col-xs-12" style="margin-right: 10px">Location</label>
<div class="col-md-3 col-sm-3 col-xs-12">
#Html.DropDownList("LocationID", null, "-- Select Location--", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.LocationID, "", new { #class = "text-danger" })
</div>
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FName)
#Html.ValidationMessageFor(model => model.FName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LName)
#Html.ValidationMessageFor(model => model.LName)
</div>
</div>
<br/>
<br/>
<div class="form-group">
<center>
<p>
<input type="submit" value="Create"/>
</p>
</center>
</div>
}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Save</button>
</div>
</div>
Also change
#Html.Action("StudentManager", "StudentController") to #Html.Action("StudentManager", "Student")
like if should be name of controller
There's a fundamental misunderstanding here about how things work. A client makes a request to a server and the server returns a response. The client, then, generally does something with that response. In the case of a web browser, it clears the current view in the tab/window, parses the response and renders it into that tab/window. There's actually a lot more that goes on, but I'm trying to keep it simplistic.
However, AJAX (or specifically the XMLHttpRequest object in JavaScript) is what you would call a thin client. It's like a little web browser within your web browser, only without all the bells and whistles. All it does is submit requests and deliver the response to a callback. That callback is a JavaScript function whose job is to do something with the response. If the goal is to replace some portion of HTML on the page, the JavaScript code in the callback must do that. It does not happen automatically.
It's also important to realize that a "partial view" is only a thing server-side. Whether MVC is returning a partial view, a normal view, or even a view composed from various partial views is all inconsequential. What the server returns to the client is just an HTML document. In the case of the client being a web browser, it then parses that HTML document and builds what's called the Document Object Model, or DOM. It then uses the DOM to "render" the page as formatted images and text.
Likewise, all an AJAX request returns is an HTML document, which is itself really just a text document with a mime type of "text/html" that informs the client that it should be treated as HTML. As I said, it's the job of the AJAX callback to do something with this response from the server, but the point here is that you can't just say "replace that partial with this HTML", because the concept of partials doesn't exist client side. All you have is a object graph (the DOM), and you must select something from the DOM and then insert the HTML into that.
Using Bootstrap in my Razor page, I am opening a modal window:
<div class="container-fluid">
<div class="navbar navbar-fixed-top navbar-default">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="offcanvas" data-target=".navbar-offcanvas" data-canvas="body">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand pull-right" href="#">
<img src="assets/img/logo-header.png" alt="Alternate Text for Image">
</a>
</div>
<div class="navbar-offcanvas offcanvas navmenu-fixed-left">
<a class="navmenu-brand" href="#">eServices</a>
<ul class="nav nav-justified">
<li>New Here?</li>
<li>Services</li>
<li>Sign In</li>
</ul>
</div>
</div>
</div>
<div class="modal fade" id="modalLogin" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<p>
<h3 class="modal-title" id="myModalLabel">Login to MyApplication</h3>
</p>
</div>
#using (Html.BeginForm("index", "home", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { role = "form", #class = "form-horizontal" }))
{
#Html.AntiForgeryToken()
<div class="form-group #Html.ValidationErrorFor(m => m.Username, "has-error has-feedback")">
<div class="col-sm-12">
#Html.FormTextBoxFor(p => p.Username, new { #class = "form-control" })
#if (!Html.IsValid(m => m.Username))
{
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
}
#Html.ValidationMessageFor(m => m.Username, null, new { #class = "help-block" })
</div>
</div>
<div class="form-group #Html.ValidationErrorFor(m => m.Password, "has-error has-feedback")">
<div class="col-sm-12">
#Html.FormPasswordFor(p => p.Password, new { #class = "form-control" })
#if (!Html.IsValid(m => m.Password))
{
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
}
#Html.ValidationMessageFor(m => m.Password, null, new { #class = "help-block" })
</div>
</div>
#Html.ValidationSummary(true, string.Empty, new { #class = "test" }, "span")
<div class=" pull-right">
<p>
<button type="submit" class="btn btn-default">#Forms.ButtonSignin</button>
</p>
<br />
<p>
#Html.ActionLink("Forgot your username?", "ForgotUsername")
</p>
<p>
#Html.ActionLink("Forgot your password?", "ForgotPassword")
</p>
</div>
}
</div>
</div>
</div>
The issue I have is that, for example, I entered an incorrect username/password combination, the form validates, but the modal window closes. Is there a way to re-open the modal window after the form has posted if the validation triggered an error?
You could add a property named IsModalShown i.e.
public class AModel
{
public bool IsModalShown { get; set; }
}
Render this as a hidden for in your view i.e.
#Html.HiddenFor(m => m.IsModalShown)
When the modal is opened set the hidden value to true, this will enable the modal state to be posted back to the controller action i.e.
$('#modalLogin').on('show.bs.modal', function (e) {
$('#IsModalShown').val(true);
})
Please note the above will depend on the version of bootstrap you are using but there are other docs on the official site
Then add the following to your view that automatically pops it up
$(function(){
#if(Model.IsModalShown)
{
$('#signin_modal').modal('show');
}
});
I had a similar problem, but didn't have a model in view. Posting my solution, in case it would help someone. I wanted to show an error message stored in TempData (in case of wrong login/password combination, on which Batuta was asking).
Controller:
public ActionResult SignIn(string login, string password)
{
if (Membership.ValidateUser(login, password))
{
// something
}
else
{
TempData["message-error"] = "Wrong combination";
}
return RedirectToAction("Index", "Home");
}
Showing the message in modal window:
#if (TempData["message-error"] != null)
{
#TempData["message-error"]
}
Opening modal in index:
#if (TempData["message-error"] != null)
{
<script type="text/javascript">
$('#myModal').modal('show');
</script>
}
Maybe not that clean, but works for me.