I'm starting to learn ASP.NET Core MVC and just found out that the toolbox is inaccessible/disabled/grayed out, so in html I cannot use <asp:Label/> tag and have to use <label></label> tag instead.
Now I am having trouble changing the string on the HTML Tag <label></label> from the backend.
For this case I already wrote runat="server" inside the tag but still an error occured that says:
The name 'lblkpj' does not exist in the current context
Here is the example html:
<label class="text-center mb-1 fw-bold" runat="server" id="lblkpj"> </label>
and C#:
if (tbl.Rows.Count > 0)
{
lblkpj.text = "Success";
}
else
{
lblkpj.text = "Failed";
}
Where am I going wrong?
Work with Razor markup.
You can implement the logic in View by declaring the variable. And use # symbol. Razor will evaluate the expression and render the output into HTML.
And make sure that you need to return the ViewModel as a List of your model objects from the Controller to View.
View
#model List<YourModel>
#{
string status = Model.Rows.Count > 0 ? "Success" : "Failed";
}
<label class="text-center mb-1 fw-bold" id="lblkpj">#status</label>
Controller
public class YourController : Controller
{
public IActionResult YourView()
{
// Mock data
List<YourModel> list = new List<YourModel>();
return View(list);
}
}
Related
I have decided to use BotDetect Captcha in my project to stop spam, however, I have not been able to check if the user has entered the correct captcha since Razor Pages doesn't support Filters.
On their site, they say to use this attribute to check if the captcha is valid
[CaptchaValidationActionFilter("CaptchaCode", "ExampleCaptcha", "Wrong Captcha!")]
However, razor pages doesn't allow attributes on page methods.
Digging into the source code of the attribute, I found this
MvcCaptcha mvcCaptcha = new MvcCaptcha(this.CaptchaId);
if (mvcCaptcha.IsSolved) { }
However when I tried that code directly in the OnPost method, mvcCaptch.IsSolved always returns false.
Checking the session variables also shows all of the BDC_ values required for this control to work so I've hit a wall here. Hoping someone could help me out. Thanks.
Official docs if it helps, although, I could'nt find any reference to Razor Pages on the site https://captcha.com/mvc/mvc-captcha.html
I found there is an attribute CaptchaModelStateValidation attribute you can apply to a Razor page model property that is bound to the captcha code input. This way you get the validation automatically in the ModelState.
Here is a sample model that validates the captcha.
public class CaptchaValidatorModel : PageModel
{
public void OnPost()
{
if (ModelState.IsValid)
{
// Perform actions on valid captcha.
}
}
[BindProperty]
[Required] // You need this so it is not valid if the user does not input anything
[CaptchaModelStateValidation("ExampleCaptcha")]
public string CaptchaCode { get; set; }
}
The page uses the code provided in the documentation sample.
#page
#model CaptchaWebApplication.Pages.CaptchaValidatorModel
#{
ViewData["Title"] = "Captcha";
}
<form method="post">
<label asp-for="CaptchaCode">Retype the code from the picture:</label>
<captcha id="ExampleCaptcha" user-input-id="CaptchaCode" />
<div class="actions">
<input asp-for="CaptchaCode" />
<input type="submit" value="Validate" />
<span asp-validation-for="CaptchaCode"></span>
#if ((HttpContext.Request.Method == "POST") && ViewData.ModelState.IsValid)
{
<span class="correct">Correct!</span>
}
</div>
</form>
Let's say that i have a navbar with a search bar, and it appears on every single page, so when the user click on the search button, it could happend 2 things:
Refresh the page if the input is empty
Redirect to a SearchResult.cshtml and show the results...
So the controller and action who handle the HTTP POST Request are Search - SearchResult respectively. I want to get the URL from the caller because the action method will need it to decide what page should redirect it.
PD: I'm using ASP.NET CORE MVC 3.1
In the Layout page, you could add a hidden field to store the current page URL, then, when click the Search button, in the SearchResult action, you could get the previous URL from the hidden field. Code as below:
_Layout.cshtml page,
<div class="search">
#{
//get current url
Uri currenturl = new Uri(String.Format("{0}://{1}{2}{3}", Context.Request.Scheme, Context.Request.Host, Context.Request.Path, Context.Request.QueryString));
}
<form asp-controller="Search" asp-action="SearchResult">
<input class="text-body" type="text" value="" name="search" />
<input name="returnurl" type="hidden" value="#currenturl" />
<input type="submit" class="btn btn-info" value="Search" />
</form>
</div>
Code in the SearchResult action:
public IActionResult SearchResult()
{
//get the returned url
var returnurl = HttpContext.Request.Form["returnurl"].ToString();
//do something
return Redirect(returnurl);
}
The screenshot as below:
What you probably want to do is submit the current path/query along with your query.
You could accomplish that by having your search form be something like this.
<form asp-controller="Search" method="get">
<input name="q" value="#Context.Request.Query["q"]" />
<input name="r" type="hidden" value="#Context.Request.GetEncodedPathAndQuery()" placeholder="Search the thing" />
</form>
Notice im using a get method here. This is to keep the search state in the browser but you can manage that however you need too. Im also using GetEncodedPathAndQuery which will need to be installed, but again the important part is to maintain the path/query(and more if this will be cross domain).
My controller will then look something like this.
[Route("/search")]
public class SearchController : Controller
{
[HttpGet]
public IActionResult Index(
[Bind(Prefix = "q")] string query,
[Bind(Prefix = "r")] string referrer)
{
IActionResult result = null;
if (string.IsNullOrWhiteSpace(query))
{
result = this.Redirect(referrer);
}
else
{
result = this.View(); // do search and return view.
}
return result ?? this.Redirect("/");
}
}
This can obviously be adjusted in anyway you need. The main thing is accepting the two values from the request and handling them properly. You might also want to validate that the referrer is an actual url since the redirect action will throw if its not.
I know I am missing something very basic. I have a HomeController and inside that there is a partial view. There is a button inside partial view which gets data(ParserModel) via ajax call. Now the single data value is not getting in _Parser.cshtml.
Here is my HomeController ajax method which calls ParserView data.
public IActionResult Parser()
{
ParserModel parser = new ParserModel();
parser.LogoPosition = "This is correct";
return PartialView("_Parser");
}
Below is my _Parser.cshtml view which is not setting the value of LogoPosition
#using PageRefine.Models
#model PageRefine.Models.ParserModel
<form asp-controller="Home" asp-action="Parser" data-ajax="true" data-ajax-update="#CustomerList">
<button type="submit" id="button1">Click</button>
<p>#Model.LogoPosition</p>#*This is giving null reference error. Here it should be "This is correct"*#
<p>#Html.RenderPartial("_Parser", Model.LogoPosition)</p>#*This is printing LogoPosition*#
</form>
Here is Index.cshtml code for partial view
<div id="CustomerList">
<partial name="_Parser" />
</div>
What should I do to get the modal values by their name in Partial View (_Parser.cshtml). Let me know if I am missing any info.
You need to pass the model to your partial view
public IActionResult Parser()
{
ParserModel parserModel = new ParserModel();
parserModel.LogoPosition = "This is correct";
return PartialView("_Parser", parserModel);
}
I have a page with many required fields. So when I click submit button required validation is firing for the first field then the second then the third and so on...
What I need to do here is , When I click on submit I have to show all errors on a page in one shot.
My requirement is to achieve this only by validating client side.
I am using an .Net core MVC application.
Below is the screenshot of my page
Can I achieve this.. Please help me..
Thanks !!
I can give you an idea to do your job using jquery custom validation.Please refer my solution.
Add custom style class to your required fields.
Example :
<input type="text" class="req-cls" >
Write Jquery function to Check Validation
$(document).ready(function () {
$('#btn1').click(function (e) {
var isValid = true;
$('.req-cls').each(function () {
if ($.trim($(this).val()) == '') {
isValid = false;
$(this).css({
"border": "1px solid red",
"background": "#FFCECE"
});
}
else {
$(this).css({
"border": "",
"background": ""
});
}
});
if (isValid == false)
e.preventDefault();
});
});
See Example here : https://jsfiddle.net/Shalitha/q2n8L9wg/24/
Just add this line in your .cshtml
<div class="validation-summary-valid" data-valmsg-summary="true">
<ul>
<li style="display: none;"></li>
</ul>
</div>
Since you need client side we are talking about JS. But with razor you can validate a few results using the model annotations. For example let's say you have this object.
public class UserCreationVO
{
[Required]
[StringLength(255)]
public string Username { get; set; }
}
Now what you need to do in your frontend (meaning your .cshtml file) is to tell asp.net to use this properties to validate. So for example:
#model UserCreationVO
<form method="post">
<input asp-for="UserName" />
<span asp-validation-for="UserName"></span>
</form>
As you can see above using asp-for is a great way to create validations using your models. Be careful you must pass as a model the object you want to validate. The asp-for tag shows a model property. So you can't pass it in a Viewbag or something. This produces some automatic html and js for you and handles it.
Furthermore you should always validate the result nevertheless in the controller. Because client side validation is for performance reasons and user experience and doesn't offer any kind of security:
public IActionResult CreateUser(UserCreationVO user)
{
if(!ModelState.IsValid)
return your_error;
}
Last but not least: You must include the JQuery unobtrusive validation library. Furthermore if you have some extra requirements like checking if a username exists (Which can't be done without contacting the server) then you can use the [Remote] attribute.
More info and reading about front-end validation with razor: here
How to use a remote attribute: Using remote validation with ASP.NET Core
EDIT:
So generally I advise to use models and create them. As you say policy is required in one form but not in another. What you should do to have a maintanable code where you simply change the attribute of your model and the validation happens you need to create a different VO. For example:
public class CreatePolicyVO
{
[Required]
public string PolicyNumber {get; set;}
}
And another object for example updating:
public class UpdatePolicyVO
{
public string PolicyNumber {get; set;}
}
Because you also need to validate them in the controller. So passing a different object allows you to use ModelState.IsValid and other MVC and razor features. Generally if a field is required in one case and not in another then you need a different model.
First, we need to add the JQuery,jquery.validate & jquery.validate.unobtrusive in our views.
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.16.0/jquery.validate.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"></script>
Then in View add required data-* attributes like:
<label for="Name">Name</label>
<input type="text" data-val="true" data-val-length="Length must be between 10 to 25" data-val-length-max="25" data-val-length-min="10" data-val-required="Please enter the name" id="Name" name="Name" value="" />
<span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
<br />
You could see that it has added the several attributes starting with data-*.
The data-* attributes are part of the HTML5, which allow us the add extra information (metadata) to the HTML element.
The Javascript unobtrusive library reads the data-val attributes and performs the client side validation in the browser when the user submits the form. These Validations are done before the form is sent over an HTTP. If there is a validation error, then the request will not be sent.
Sitecore 7.1v1, most recent Glass Mapper, MVC4. When we submit the form POST, we get no layout with the return View. I'd prefer not to have to redirect to another page since this is supposed to be a wizard-like experience. This is also lightweight enough not to require Ajax, although we could use it as a last resort. I can't find who to make sure that while returning the View that we get the layout as well. I'm new to Sitecore MVC and pretty new at MVC in general. The PageBase that's referenced is a Custom Model using Glass.
We have the following Controller Rendering:
public class RegistrationController : Controller
{
[HttpGet]
public ActionResult VerifyAccount()
{
return View("~/Views/Public/Wizards/Registration/VerifyAccount.cshtml",
new SitecoreContext().GetCurrentItem<PageBase>());
}
[HttpPost]
public ActionResult CreateProfile()
{
ViewBag.Name = Request["VerificationType"];
ViewBag.Step = 2;
return View("~/Views/Public/Wizards/Registration/CreateProfile.cshtml",
new SitecoreContext().GetCurrentItem<PageBase>());
}
}
The default action for this is VerifyAccount(). This renders as expected. The initial view is as follows:
#inherits Glass.Mapper.Sc.Web.Mvc.GlassView<Public.Model.GlassModel.Primary.PageBase>
<div>
<h3>#Editable(a => a.Title)</h3>
<p>
#Editable(a => a.Description)
</p>
<hr />
#using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, FormMethod.Post))
{
#Html.Sitecore().FormHandler("Registration", "CreateProfile")
#Html.ValidationSummary(true, "Verification Not Selected.")
<fieldset>
#Sitecore.Globalization.Translate.Text("$Registration.VerificationTitle")
#{ var validations = new SitecoreContext().GetItem<GlassFrameBase>(Guid.Parse("{3694FC43-3DB7-470A-A1E9-2649856AAF10}"));}
<select id="VerType" name="VerificationType">
#foreach (var validation in validations.GetChildren<VerificationMethod>())
{
<option value="#validation.MethodValue">#validation.MethodName</option>
}
</select>
<input type="submit" value="Next" />
</fieldset>
}
This posts back to the CreateProfile() Method. This part works great. The only issue is that when it returns the view this time, it returns just the view without the layout.
The final view is as follows:
#using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, FormMethod.Post))
{
#Html.Sitecore().FormHandler()
<p>
<b>Verification Type Was: </b>#ViewBag.Name
</p>
<p>#ViewBag.Step</p>
<input type="hidden" value="ThisIsATest" name="TestHidden" id="TestHidden"/>
<input type="submit" name="back" value="Back" /><br />
<input type="submit" name="next" value="Next" />
}
Everything else is working exactly as expected but I'm missing something important that loads the Layout on the return trip.
I have noticed this before as well and I think it relates to this line:
#Html.Sitecore().FormHandler("Registration", "CreateProfile")
It seems to bypass the standard rendering pipeline and just call the target action. I have written a blog post on how you can control calls to different action on multiple controllers. this might help:
http://www.experimentsincode.com/?p=425
Try changing the return type of CreateProfile from ActionResult to PartialViewResult, and then return View("... to return PartialView("...
Also, here's a post about what you can return for Sitecore Controller Renderings.
http://mhwelander.net/2014/04/09/sitecore-controller-rendering-action-results-what-can-i-return/
I haven't looked deeply into form posting with Controller Renderings, but if the above suggestion doesn't work then maybe consider the execution lifestyle used in Sitecore MVC (mentioned in the post).