I have a custom asp.net server component that is rendered as below:
<div id="divContentRating">
<div id="divAskForRating">
#Question
<br />
<a id="likeIcon"><img src="#PositiveRateIconPath"/></a>
<a id="neutralIcon"><img src="#NeutralRateIconPath"/></a>
<a id="unlikeIcon"><img src="#NegativeRateIconPath"/></a>
</div>
<div id="divPositiveRating">
<div>
<img src="#PositiveRateIconPath"/> #PositiveAnswerMessage <br />
Güncelle
</div>
</div>
<div id="divNegativeRating">
<div>
<img src="#NegativeRateIconPath"/> #NegativeAnswerMessage <br />
Güncelle
</div>
</div>
<div id="divNeutralRating">
<div>
<img src="#NeutralRateIconPath"/> #NeutralAnswerMessage <br />
Güncelle
</div>
</div>
<input type="hidden" id="HasRated" value="#HasRated">
<input type="hidden" id="Rate" value="#Rate">
<input type="hidden" id="ContentKey" value="#ContentKey">
<input type="hidden" id="RatingId" value="#RatingId">
</div>
Is it possible to handle the click on the images in my web control? I mean, I want to do some operations when user clicks on the images, but I want to code these in my web control.
Here is my web control:
[DefaultProperty("ContentKey")]
[ToolboxData("<{0}:ContentRating runat=server></{0}:ContentRating>")]
public class ContentRating : WebControl
{
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string ContentKey
{
get
{
String s = (String)ViewState["ContentKey"];
return ((s == null) ? "[" + this.ID + "]" : s);
}
set
{
ViewState["ContentKey"] = value;
}
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string PositiveRateIconPath
{
get
{
String s = (String)ViewState["PositiveRateIconPath"];
return ((s == null) ? "[" + this.ID + "]" : s);
}
set
{
ViewState["PositiveRateIconPath"] = value;
}
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string NegativeRateIconPath
{
get
{
String s = (String)ViewState["NegativeRateIconPath"];
return ((s == null) ? "[" + this.ID + "]" : s);
}
set
{
ViewState["NegativeRateIconPath"] = value;
}
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string NeutralRateIconPath
{
get
{
String s = (String)ViewState["NeutralRateIconPath"];
return ((s == null) ? "[" + this.ID + "]" : s);
}
set
{
ViewState["NeutralRateIconPath"] = value;
}
}
protected override void RenderContents(HtmlTextWriter output)
{
ContentRatingSettings contentRatingSettings = GetContentRatingSettings(this.ContentKey);
if (!contentRatingSettings.Visible)
{
output.Write(string.Empty);
return;
}
StringBuilder builder = new StringBuilder(#"
<div id=""divContentRating"">
<div id=""divAskForRating"">#Question
<br />
<a id=""likeIcon""><img src=""#PositiveRateIconPath""/></a>
<a id=""neutralIcon""><img src=""#NeutralRateIconPath""/></a>
<a id=""unlikeIcon""><img src=""#NegativeRateIconPath""/></a>
</div>
<div id=""divPositiveRating"">
<div>
<img src=""#PositiveRateIconPath""/> #PositiveAnswerMessage <br />
Güncelle
</div>
</div>
<div id=""divNegativeRating"">
<div>
<img src=""#NegativeRateIconPath""/> #NegativeAnswerMessage <br />
Güncelle
</div>
</div>
<div id=""divNeutralRating"">
<div>
<img src=""#NeutralRateIconPath""/> #NeutralAnswerMessage <br />
Güncelle
</div>
</div>
<input type=""hidden"" id=""HasRated"" value=""#HasRated"">
<input type=""hidden"" id=""Rate"" value=""#Rate"">
<input type=""hidden"" id=""ContentKey"" value=""#ContentKey"">
<input type=""hidden"" id=""RatingId"" value=""#RatingId"">
<script type=""text/javascript"">
$(document).ready(function () {
var protocol = location.protocol;
var host = window.location.host;
if ($(""#HasRated"").val() == ""True"")
{
var rate = $(""#Rate"").val();
if (rate == 1) {
setPositiveRatedView();
}
else if (rate == 0) {
setNeutralRatedView();
}
else if (rate == -1) {
setNegativeRatedView();
}
else {
setNotRatedView();
}
}
else {
setNotRatedView();
}
$(""#likeIcon"").click(function () {
alert(""like"");
setPositiveRatedView();
ratePage(1, """");
});
$(""#neutralIcon"").click(function () {
alert(""neutral"");
setNeutralRatedView();
ratePage(0, """");
});
$(""#unlikeIcon"").click(function () {
alert(""unlike"");
setNegativeRatedView();
//mkMPopClc('NegativeRatingReason', 200, 300, 0, 0);
});
$("".updateRate"").click(function () {
setNotRatedView();
});
function setNotRatedView() {
$(""#divNeutralRating"").fadeOut();
$(""#divPositiveRating"").fadeOut();
$(""#divAskForRating"").fadeIn();
$(""#divNegativeRating"").fadeOut();
}
function setPositiveRatedView()
{
$(""#divNegativeRating"").fadeOut();
$(""#divNeutralRating"").fadeOut();
$(""#divAskForRating"").fadeOut();
$(""#divPositiveRating"").fadeIn();
}
function setNegativeRatedView() {
$(""#divNeutralRating"").fadeOut();
$(""#divPositiveRating"").fadeOut();
$(""#divAskForRating"").fadeOut();
$(""#divNegativeRating"").fadeIn();
}
function setNeutralRatedView() {
$(""#divNegativeRating"").fadeOut();
$(""#divPositiveRating"").fadeOut();
$(""#divAskForRating"").fadeOut();
$(""#divNeutralRating"").fadeIn();
}
function ratePage(rating, comment)
{
//alert(rating + """" """" + comment);
var contentKey = $(""#ContentKey"").val();
var hasRated = $(""#HasRated"").val();
var ratingId = $(""#RatingId"").val();
}
});
</script>
</div>");
SetTrackingCookie();
builder.Replace("#ContentKey", this.ContentKey);
builder.Replace("#PositiveRateIconPath", this.PositiveRateIconPath);
builder.Replace("#NeutralRateIconPath", this.NeutralRateIconPath);
builder.Replace("#NegativeRateIconPath", this.NegativeRateIconPath);
builder.Replace("#Question", contentRatingSettings.Question);
builder.Replace("#PositiveAnswerMessage", contentRatingSettings.PositiveAnswerMessage);
builder.Replace("#NeutralAnswerMessage", contentRatingSettings.NeutralAnswerMessage);
builder.Replace("#NegativeAnswerMessage", contentRatingSettings.NegativeAnswerMessage);
output.Write(builder);
}
}
Thanks in advance,
If you want to attach events to controls, overriding CompositeControl will be a lot easier than WebControl.
CreateChildControl can route the event to its child but WebControl can't.
Please keep it mind that it is an alternative approach to your question because it requires some of changes (from your original code).
Depending on what you want to do, the quickest option will be to add runat="server" tag to the image control along with an on click event handler than points to a function.
This will perform a postback to the asp page whenever the image is clicked.
If the post back is not desired then you will need to wire up javascript to do an ajax based postback and appropriate client/server handlers.
Related
I'm using PagedList library for pagination and also have ordering and filtering. The problem is that after submit of order/filter request the pagination resets to page 1 but I have to keep it at current page? How can this be achieved? I also don't know if this is the right behavior but I was told to it is.
This is my controller:
public class ProductSearchBlockController : BlockController<ProductSearchBlock>
{
private readonly IRepository<Products> _productsRepository;
public ProductSearchBlockController(IRepository<Products> productsRepository)
{
_productsRepository = productsRepository;
}
public override ActionResult Index(ProductSearchBlock currentBlock)
{
if (Session[SessionConstants.Products] == null)
{
Session[SessionConstants.Products] = _productsRepository.All();
}
var sessionProducts = Session[SessionConstants.Products] as IEnumerable<Products>;
var searchString = Request.QueryString.Get(RequestQueryConstants.SearchString);
var orderBy = Request.QueryString.Get(RequestQueryConstants.OrderBy);
var pageNumber = Request.QueryString.Get(RequestQueryConstants.PageNumber);
if (string.IsNullOrEmpty(orderBy))
{
orderBy = "default";
}
if (!string.IsNullOrEmpty(searchString))
{
var result = sessionProducts.Where(p => p.OrganizaitonId.Contains(searchString) ||
p.ProductName.Contains(searchString)).ToList();
Session[SessionConstants.ProductsResult] = result;
}
else
{
var result = sessionProducts.ToList();
Session[SessionConstants.ProductsResult] = result;
}
var productsResult = Session[SessionConstants.ProductsResult] as List<Products>;
productsResult = TableDisplayHelper.OrderedProducts(orderBy, productsResult);
var viewModel = new ProductSearchBlockViewModel();
viewModel.Products = productsResult.ToPagedList(int.Parse(pageNumber), 2);
viewModel.PageNumber = int.Parse(pageNumber);
viewModel.OrderBy = orderBy;
viewModel.FilterBy = searchString;
viewModel.Options = currentBlock.Options;
return PartialView(viewModel);
}
public ActionResult GetTableData(string searchString, string orderBy, int? page)
{
if (searchString == null && orderBy == null)
{
return Redirect(PageHelper.CurrentPageUrl());
}
if (searchString != null)
{
page = 1;
}
int pageNumber = page ?? 1;
var orderByQuery = UriUtil.AddQueryString(PageHelper.CurrentPageUrl(), RequestQueryConstants.OrderBy, orderBy.ToString());
var SearchStringQuery = UriUtil.AddQueryString(orderByQuery, RequestQueryConstants.SearchString, searchString);
var finalUrl = UriUtil.AddQueryString(SearchStringQuery, RequestQueryConstants.PageNumber, pageNumber.ToString());
return Redirect(finalUrl);
}
This is the view:
<div class="block esproductsearchblock col-lg-12 col-md-12 col-sm-12 col-xs-12 ">
<div class="es-product-search-block es-product-search-block-index b-spacing-default fonts-regular template-base block-wrapper">
<div class="template-search-block wrapper-fullsize" data-is-pagination-enabled="True" style="opacity: 1; pointer-events: auto;">
<section class="product-search wrapper-940" style="opacity: 1; pointer-events: auto;">
#using (Html.BeginForm("GetTableData", "ProductSearchBlock", FormMethod.Get))
{
<span>Order By</span>
<select id="orderBySelect" name="orderBy" aria-hidden="true">
#if (Model.Options != null)
{
foreach (var item in Model.Options)
{
if (Model.OrderBy == item.Trim().ToLower())
{
<option value="#item" selected>#item</option>
}
else
{
<option value="#item">#item</option>
}
}
}
</select>
<div class="search-field bottom-aligned-m">
<input id="search-field-inputid" class="search-field-input" name="searchString" placeholder="Search" value="#Model.FilterBy">
<i class="fa fa-close"></i>
</div>
<button class="btn">Submit Search</button>
<a class="btn" href="/ProductSearchBlock/GetTableData">Clear Search</a>
<div id="distribution-status-filter" data-distribution-status-filter-id="251" data-distributon-status-options="Phased out,Mature,Active"></div>
}
</section>
<div class="search-results-table wrapper-940">
<section class="results">
<div class="products">
#foreach (var product in Model.Products)
{
<div class="product product-data">
<div class="title-container">
<p class="product-name">#product.ProductName</p>
</div>
<div class="group">
<p class="indication">#product.OrganizaitonId</p>
</div>
<div class="price">
<h6>Price per Unit</h6>
<p class="small-text bold">
#product.Price <span class="product-price__currency-marker">€</span>
</p>
</div>
#using (Html.BeginForm("AddToCart", "ProductSearchBlock", FormMethod.Get))
{
<div class="float-container">
<div class="float-child">
<h6>Quantity</h6>
<input min="1" style="width:50%" type="number" name="quantity" value="0">
<input hidden type="number" name="id" value="#product.Id">
</div>
<div class="float-child">
<button class="cart-btn primary-btn">Add</button>
</div>
</div>
}
</div>}
</div>
#Html.PagedListPager(Model.Products, page => Url.Action("GetTableData", "ProductSearchBlock",
new
{
page,
orderBy = Model.OrderBy,
searchString = Model.FilterBy
}),
new PagedListRenderOptions
{
ContainerDivClasses = new List<string> { "pagination" }, LiElementClasses = new List<string> { "paginationSpan" }
});
</section>
</div>
</div>
</div>
Found a solution maybe there is a better version but current one works.
Added parameter pageNumber to form and changed form to post:
#using (Html.BeginForm("GetTableData", "ProductSearchBlock", new { pageNumber=Model.PageNumber}, FormMethod.Post))
In controller get the current page number and check if exists set page to current page
public ActionResult GetTableData(string searchString, string orderBy, int? page)
{
var currentPage = Request.QueryString.Get(RequestQueryConstants.PageNumber);
if (searchString == null && orderBy == null)
{
return Redirect(PageHelper.CurrentPageUrl());
}
if(currentPage != null)
{
page = int.Parse(currentPage);
}
var orderByQuery = UriUtil.AddQueryString(PageHelper.CurrentPageUrl(), RequestQueryConstants.OrderBy, orderBy.ToString());
var SearchStringQuery = UriUtil.AddQueryString(orderByQuery, RequestQueryConstants.SearchString, searchString);
var finalUrl = UriUtil.AddQueryString(SearchStringQuery, RequestQueryConstants.PageNumber, page.ToString());
return Redirect(finalUrl);
}
I have two inputs that I need to validate against each other. They are a minimum and maximum. Here is the part of my view defining them.
<div class="form-group">
<label asp-for="MinTubes" class="control-label"></label>
<input asp-for="MinTubes" class="form-control" />
<span asp-validation-for="MinTubes" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MaxTubes" class="control-label"></label>
<input asp-for="MaxTubes" class="form-control" />
<span asp-validation-for="MaxTubes" class="text-danger"></span>
</div>
And here are the properties that they are mapped to:
[Display(Name = "Min Tubes")]
[MinToValidation("MaxTubes")]
public int MinTubes { get; set; }
[Display(Name = "Max Tubes")]
[MaxToValidation("MinTubes")]
public int MaxTubes { get; set; }
This results in <input type='number'> elements with labels and validation messages.
I have created two custom validation attributes to work with them. I'll only post the MaxToValidationAttribute class, as the other one is functionally identical.
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System;
using System.ComponentModel.DataAnnotations;
namespace CCM_Util.CustomAttributes
{
public class MaxToValidationAttribute : ValidationAttribute, IClientModelValidator
{
public MaxToValidationAttribute(string min)
: base("{0} must be greater than or equal to {1}")
{
Min = min;
}
public string Min { get; set; }
public string FormatErrorMessage(string name, string minName)
{
return string.Format(ErrorMessageString, name, minName);
}
protected override ValidationResult
IsValid(object firstValue, ValidationContext validationContext)
{
var firstComparable = firstValue as IComparable;
var secondComparable = GetSecondComparable(validationContext);
if (firstComparable != null && secondComparable != null)
{
if (firstComparable.CompareTo(secondComparable) < 0)
{
object obj = validationContext.ObjectInstance;
var thing = obj.GetType().GetProperty(Min);
var displayName = (DisplayAttribute)Attribute.GetCustomAttribute(thing, typeof(DisplayAttribute));
return new ValidationResult(
FormatErrorMessage(validationContext.DisplayName, displayName.GetName()));
}
}
return ValidationResult.Success;
}
protected IComparable GetSecondComparable(
ValidationContext validationContext)
{
var propertyInfo = validationContext
.ObjectType
.GetProperty(Min);
if (propertyInfo != null)
{
var secondValue = propertyInfo.GetValue(
validationContext.ObjectInstance, null);
return secondValue as IComparable;
}
return null;
}
public void AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val-min", Min);
context.Attributes.Add("data-val-ismax", "true");
}
}
}
Then, in Default.js, I have the following function being run as part of my document.ready function.
function minMaxValidate() {
$("input[data-val-ismin='true']").each(function (i, ele) {
$(ele).change(function () {
var maxName = $(this).attr("data-val-max");
var minName = $(this).attr("name");
var minValue = parseFloat($(this).val());
var max = $("input[data-val-ismax='true'][name='" + maxName + "']");
var maxValue = max.val();
if (maxValue == "") { return }
maxValue = parseFloat(maxValue);
var validationMessage = $("span[data-valmsg-for='" + $(this).attr("name") + "']");
if (minValue > maxValue) {
validationMessage.html(minName + " must not be greater than " + maxName);
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
});
$("input[data-val-ismax='true']").each(function (i, ele) {
$(ele).change(function () {
var minName = $(this).attr("data-val-min");
var maxName = $(this).attr("name");
var maxValue = parseFloat($(this).val());
var min = $("input[data-val-ismin='true'][name='" + minName + "']");
var minValue = min.val();
if (minValue == "") { return }
minValue = parseFloat(minValue);
var validationMessage = $("span[data-valmsg-for='" + $(this).attr("name") + "']");
if (minValue > maxValue) {
validationMessage.html(maxName + " must not be less than " + minName);
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
});
}
The makeError and makeValid functions essentially just change the class of validationMessage to field-validation-error and field-validation-valid respectively, and they manage the submit handler.
I know that this type of validation setup works, because I am using it elsewhere without trouble.
I have stepped through the change handlers and they are working just as they should. However, after the error message shows up and the code exits, it disappears again. My guess is that .NET's default number input validation is taking over, and since the inputs are both valid numbers, it removes the error message.
Is there any way to disable .NET's default validation on number type inputs so that I can handle it myself and not have external black box code messing with my stuff?
Thanks.
EDIT:
Here are the view and Default.js files in their entirety, just in case.
#model Coils.CoilParts.Distributor
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#{
ViewData["Title"] = ViewData["ProgramName"];
}
<h1>Create</h1>
<h4>Distributor</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Material" class="control-label"></label>
#Html.DropDownListFor(m => m.Material.Key, ((IEnumerable<SelectListItem>)ViewData["Materials"]))
<span asp-validation-for="Material" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Type" class="control-label"></label>
<input asp-for="Type" class="form-control" />
<span asp-validation-for="Type" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MinTubes" class="control-label"></label>
<input asp-for="MinTubes" class="form-control" />
<span asp-validation-for="MinTubes" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MaxTubes" class="control-label"></label>
<input asp-for="MaxTubes" class="form-control" />
<span asp-validation-for="MaxTubes" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InletSize" class="control-label"></label>
<input asp-for="InletSize" class="form-control" />
<span asp-validation-for="InletSize" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PartNumber" class="control-label"></label>
<input asp-for="PartNumber" class="form-control" />
<span asp-validation-for="PartNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Weight" class="control-label"></label>
<input asp-for="Weight" class="form-control" />
<span asp-validation-for="Weight" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
$(document).ready(function () {
breadcrumbs();
measurementsValidate();
minMaxValidate();
});
var cgi_menus = {
'act': "the Accounting Menu",
'adm': "the Administation Menu",
'car': "the Corrective Action Request Menu",
'cprA': "the A+Pro Menu",
'cprC': "the CoilPro Menu",
'crm': "the Customer Relations Menu",
'dms': "the Document Management Menu",
'eng': "the Engineering Menu",
'etb': "the Engineering Toolbox Menu",
'ldc': "the Refrigeration Load Simulator Menu",
'mgt': "the Management Menu",
'prd': "the Production Menu",
'pur': "the Purchasing Menu",
'qcd': "the Quality Control Menu",
'rpt': "the Report Menu",
'sls': "the Sales Menu",
'sup': "the Administrator's Menu",
'usr': "the User Management Menu",
'utl': "the Utility Menu",
};
function breadcrumbs() {
var tab = {};
localStorage[curURL] = curProgram;
if (sessionStorage.tab) {
tab = JSON.parse(sessionStorage.tab);
}
else {
tab.cur_url = "";
tab.prev_url = "";
tab.history = [];
}
// handle coming from an existing Perl CGI menu
if (!tab.prev_url && document.referrer) {
var menu_info = document.referrer.match(/cgi-s[\\/](\w{3})[\\/]menu(\w?)\.cgi/);
var referrer = new URL(document.referrer);
if (menu_info && referrer.hostname === document.location.hostname) {
tab.cur_url = document.referrer;
var cgi_area = menu_info[1];
if (cgi_area == "cpr") { cgi_area += menu_info[2]; }
localStorage[tab.cur_url] = cgi_menus[cgi_area];
}
}
tab.time = Date.now();
tab.history.push(tab.prev_url);
tab.prev_url = tab.cur_url;
tab.cur_url = curURL;
if (tab.prev_url == tab.cur_url) {
tab.prev_url = tab.history.pop();
}
else if (tab.cur_url == tab.history[tab.history.length - 1]) {
tab.history.pop();
tab.prev_url = tab.history.pop();
}
if (tab.prev_url) {
$("#breadcrumbs").css("display", "inline-block");
$("#breadcrumbs").attr("href", tab.prev_url);
$("#breadcrumbs").html("< Back to " + localStorage[tab.prev_url]);
}
sessionStorage.tab = JSON.stringify(tab);
}
function minMaxValidate() {
$("input[data-val-ismin='true']").each(function (i, ele) {
$(ele).change(function () {
var maxName = $(this).attr("data-val-max");
var minName = $(this).attr("name");
var minValue = parseFloat($(this).val());
var max = $("input[data-val-ismax='true'][name='" + maxName + "']");
var maxValue = max.val();
if (maxValue == "") { return }
maxValue = parseFloat(maxValue);
var validationMessage = $("span[data-valmsg-for='" + $(this).attr("name") + "']");
if (minValue > maxValue) {
validationMessage.html(minName + " must not be greater than " + maxName);
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
});
$("input[data-val-ismax='true']").each(function (i, ele) {
$(ele).change(function () {
var minName = $(this).attr("data-val-min");
var maxName = $(this).attr("name");
var maxValue = parseFloat($(this).val());
var min = $("input[data-val-ismin='true'][name='" + minName + "']");
var minValue = min.val();
if (minValue == "") { return }
minValue = parseFloat(minValue);
var validationMessage = $("span[data-valmsg-for='" + $(this).attr("name") + "']");
if (minValue > maxValue) {
validationMessage.html(maxName + " must not be less than " + minName);
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
});
}
function measurementsValidate() {
$("input[data-val-measurement='true']").each(function (i, ele) {
var enforceUnits = $(ele).attr("data-val-units");
var units = "";
var hasMax = $(ele).attr("data-val-max");
var max = 0;
var hasMin = $(ele).attr("data-val-min");
var min = 0;
var value = $(ele).val();
var validationRegex = /[0-9/.]+ [a-z./\^0-9*()]+/i;
var name = $("label[for='" + $(ele).attr("name") + "']").html();
var validationMessage = $("span[data-valmsg-for='" + $(ele).attr("name") + "']");
if (typeof (enforceUnits) !== undefined && typeof (enforceUnits) !== false) {
enforceUnits = true;
units = $(ele).attr("data-val-units");
if (hasMax != null && hasMax != false) {
hasMax = true;
max = $(ele).attr("data-val-max");
}
if (hasMin != null && hasMin != false) {
hasMin = true;
min = $(ele).attr("data-val-min");
}
$(ele).change(function () {
var value = $(this).val(); // don't know why this has to be re-evaluated, but it does
if (!value.match(validationRegex)) {
validationMessage.html(name + " must be a valid Measurement. (example: 12 in)");
makeError(validationMessage);
}
else {
$.post("/Validations/Measurements", { EnforceUnits: enforceUnits, Units: units, HasMax: hasMax, Max: max, HasMin: hasMin, Min: min, Value: value })
.done(function (result) {
if (result == "true") {
validationMessage.html("");
makeValid(validationMessage);
}
else {
validationMessage.html(name + result);
makeError(validationMessage);
}
})
.fail(function () {
validationMessage.html("");
makeValid(validationMessage);
});
}
});
}
else {
$(ele).change(function () {
if (!value.match(validationRegex)) {
validationMessage.html(name + " must be a valid Measurement. (example: 12 in)");
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
}
});
}
function makeError(ele) {
$(ele).removeClass("field-validation-valid");
$(ele).addClass("field-validation-error");
$(ele).closest("form").unbind("submit");
$(ele).closest("form").submit(function () { return false });
}
function makeValid(ele) {
$(ele).removeClass("field-validation-error");
$(ele).addClass("field-validation-valid");
$(ele).closest("form").unbind("submit");
$(ele).closest("form").submit(checkFormValidation);
}
function checkFormValidation() {
if ($(this).find(".field-validation-error")[0]) {
return false;
}
return true;
}
EDIT 2:
Here's a GIF of what is happening: https://i.imgur.com/eAiqxQJ.mp4
As is so often the case, the solution is "If you can't beat them, join them".
Instead of disabling jQuery validation on the elements that I am custom handling, the solution is just to lean into the jQuery validation library and use it the proper way. Everything remains the same on the .NET side, but the minMaxValidate() function becomes this:
function minMaxValidate() {
$.validator.addMethod("maxTo", function (value, element, param) {
var $element = $(element), $min;
if (typeof (param) === "string") {
$min = $(param);
} else {
$min = $("input[name='" + $element.attr("data-val-min") + "']");
}
if (this.settings.onfocusout) {
$min.off(".validate-maxTo").on("blur.validate-maxTo", function () {
$element.valid();
});
}
return parseInt(value) >= parseInt($min.val());
}, "Max must not be less than min");
$("input[data-val-ismax]").each(function (i, ele) {
$(ele).rules('add', { maxTo: true });
});
$.validator.addMethod("minTo", function (value, element, param) {
var $element = $(element), $max;
if (typeof (param) === "string") {
$max = $(param);
} else {
$max = $("input[name='" + $element.attr("data-val-max") + "']");
}
if (this.settings.onfocusout) {
$max.off(".validate-minTo").on("blur.validate-minTo", function () {
$element.valid();
});
}
return parseInt(value) <= parseInt($max.val());
}, "Min must not be greater than max");
$("input[data-val-ismin]").each(function (i, ele) {
$(ele).rules('add', { minTo: true });
});
}
This adds methods and rules for the normal jQuery validation to run itself.
It does exactly what I want. Thanks to This post for help.
I am developing a ASP.NET MVC 4 web api to show product image associated with a company. In the database I have stored CompanyID & CompanyProductImageURL or CompanyProductImageFilepath. Now using my web api, when I click on 'Show Image' button, I want to show the product image on the same page. Right now, the url is localhost:1111/ViewCompanyProductImage.html ; when I enter CompanyID =31 & click on 'Show Image' button new tab opens with url http://localhost:1111/api/Images/?CompanyID=31 and then the CompanyProductImageURL or CompanyProductImageFilepath associated with that Company opens in another tab. I want the image to show up in localhost:1111/ViewCompanyProductImage.html under the 'SHow Image' button. Here's the code I have.
webapiconfig.cs
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "ImagesApi",
routeTemplate: "api/Images/{companyid}"
defaults: new { Controller = "Images", companyid = #"\d+" }
);}
----Controller
public class ImagesController : ApiController
{
private static T ConvertFromDBVal<T>(object obj)
{
if (obj == null || obj == DBNull.Value)
{
return default(T); // returns the default value for the type
}
else
{
return (T)obj;
}
}
[System.Web.Http.AcceptVerbs("GET")]
public HttpResponseMessage Get(int companyid)
{
Images oldImages = new Images();
string sql = "select companyid,companyproducturl from [dbo].[CompanyImage] WHERE companyid = #companyid";
using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["connection"].ConnectionString))
{
using (SqlCommand query = new SqlCommand(sql, connection))
{
SqlDataReader rdr;
query.Parameters.Add(new SqlParameter("#companyid", companyid));
query.CommandType = CommandType.Text;
connection.Open();
query.CommandTimeout = 90;
rdr = query.ExecuteReader();
if (rdr != null)
{
while (rdr.Read())
{
oldImages.companyid = ConvertFromDBVal<int>(rdr["companyid"]);
oldImages.companyproducturl = ConvertFromDBVal<string>(rdr["companyproducturl"]);
}
}
}
}
if (oldImages.companyid == 0 )
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, String.Format("No records found for companyid: {0} ", companyid)));
}
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
System.Diagnostics.Process.Start(oldImages.imageproducturl);
return response;
}
---view
public class Images
{
[Required(AllowEmptyStrings = false, ErrorMessage = "companyid Required")]
[Range(1, 10000)]
public int companyid { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "imageproducturl Required")]
public string companyproducturl { get; set; }
}
--index.cshtml
<div id="body">
<section class="featured">
<div class="content-wrapper">
<hgroup class="title">
<h1> Web API!</h1>
</hgroup>
</div>
</section>
<section class="content-wrapper main-content clear-fix">
<p>
For API documentation: #Html.ActionLink("API", "Index", "Help", new { area = "" }, null)
</p>
<p>
View Company Images:Click Here!
</p>
</section>
</div>
--ViewCompanyProductImage.html
<div class="jumbotron" align="center">
<h1>Images Web API</h1>
<p class="lead"></p>
</div>
<div class="row">
<div class="col-md-4" align="center">
<div class="first" align="center">
<form action="api/Images/" method="get" target="_blank">
companyid:
<br />
<input type="text" name="companyid"><br>
<td>
<input type="submit" value="Show Image" />
</form>
</div>
</div>
</div>
How can I show product image on the localhost:1111/ViewCompanyProductImage.html itself?
Thanks
R
You can do this using JavaScript.
Place an image element on the page, give it an ID and on button click, instead of submit, find the image element and set its src property to the desired URL.
<img src="" id="companyImage" />
<input type="text" name="companyid" />
<input type="button" value="Show Image" onclick="previewImage" />
And then in JS:
function previewImage() {
var companyId = getElementById('companyid').value;
getElementById('companyImage').src = "api/Images/?companyID=" + companyId;
}
I built a dynamic jquery menu c# (VS2013) with bootstrap 3.0 that works fine on load but when I cliked on link item menu by using calling ajax the cursor pass in action view of controller but doesn't render it. I tried using Ajax.Actionlink and this menu simple clear after clicked on link menu item.
This is my _layout, and I build menuClever:
<body>
<div class="navmenu navmenu-default navmenu-fixed-left">
<div class="scrollable">
<div class="col-lg-12">
<div id="menuClever">
</div>
</div>
</div>
</div>
<div class="canvas">
<div class="navbar navbar-default navbar-fixed-top">
<button type="button" class="navbar-toggle" data-toggle="offcanvas" data-recalc="false" data-target=".navmenu" data-canvas=".canvas">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="container fluid">
<div class="container body-content" id="funcaoContainer">
#Html.Partial("_LoginPartial")
<p></p>
<p>#RenderBody()</p>
</div>
</div>
</div>
#RenderSection("scripts", required: false)
</body>
And this is my jquery Menu:
$.fn.menuClever = function (atributos, opcoes) {
var defaults = {
propriedades: {}
};
var r = {
registros: atributos
};
var p = {
registros: []
};
if (opcoes) {
$.extend(defaults, opcoes);
var titulo = '';
titulo += '<h4>';
titulo += defaults.tituloMenu;
titulo += '</h4>';
$('#menuClever').prepend(titulo);
var menuItem = '';
var idFuncionalidadeAnterior = 0;
var nivelAnterior = 0;
var qtdItems = 0;
if (r.registros.length > 0) {
idFuncionalidadeAnterior = r.registros[0]['IdFuncionalidadeAnterior'];
nivelAnterior = r.registros[0]["Nivel"];
}
for (var i = 0; i < r.registros.length; i++) {
if (r.registros[i]['Nivel'] > nivelAnterior) {
menuItem += '<ul>';
}
else
if (r.registros[i]['Nivel'] < nivelAnterior) {
menuItem += '</ul> </li> </ul> ';
if (r.registros[i]['IdTipoFuncionalidade'] == 1) {
menuItem += '<ul>';
}
}
if (r.registros[i]['IdTipoFuncionalidade'] == 1) {
menuItem += '<li>' + r.registros[i]['Funcionalidade'] + '<span class="glyphicon arrow"></span>';
}
else {
if (r.registros[i]['Parametros'] != null) {
menuItem += '<li><a class="funcaoClever" data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#funcaoContainer" href="' +
r.registros[i]['Url'] + r.registros[i]['Parametros'] + '">' + r.registros[i]['Funcionalidade'] + '</a></li>';
}
else {
menuItem += '<li><a class="funcaoClever" data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#funcaoContainer" href="' +
r.registros[i]['Url'] + '">' + r.registros[i]['Funcionalidade'] + '</a></li>';
}
}
nivelAnterior = r.registros[i]['Nivel'];
idFuncionalidadeAnterior = r.registros[i]['IdFuncionalidadeAnterior'];
}
menuItem += '</ul>';
$('#menuClever').append(menuItem);
}
}
})(jQuery);
I made a test with this ajax too:
$.ajax({
type: "GET",
url: a_href,
crossDomain: true,
error: function (result) {
alert('Oh no: ' + result.responseText)
}
});
I have a server control as below:
[DefaultProperty("ContentKey")]
[ToolboxData("<{0}:ContentRating runat=server></{0}:ContentRating>")]
public class ContentRating : WebControl
{
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string ContentKey
{
get
{
String s = (String)ViewState["ContentKey"];
return ((s == null) ? "[" + this.ID + "]" : s);
}
set
{
ViewState["ContentKey"] = value;
}
}
protected override void RenderContents(HtmlTextWriter output)
{
StringBuilder builder = new StringBuilder(#"<div id=""divContentRating"">
<div id=""divAskForRating"">
#Question
<br />
<a id=""likeIcon""><img src=""~/Content/Images/like.jpg""/></a>
<a id=""neutralIcon""><img src=""~/Content/Images/neutral.jpg""/></a>
<a id=""unlikeIcon""><img src=""~/Content/Images/unlike.jpg""/></a>
</div>
<div id=""divPositiveRating"">
<div>
<img src=""~/Content/Images/like.jpg""/> #PositiveAnswerMessage <br />
Güncelle
</div>
</div>
<div id=""divNegativeRating"">
<div>
<img src=""~/Content/Images/unlike.jpg""/> #NegativeAnswerMessage <br />
Güncelle
</div>
</div>
<div id=""divNeutralRating"">
<div>
<img src=""~/Content/Images/neutral.jpg""/> #NeutralAnswerMessage <br />
Güncelle
</div>
</div>
<input type=""hidden"" id=""HasRated"" value=""False"">
<input type=""hidden"" id=""Rate"" value=""Rate"">
<input type=""hidden"" id=""ContentKey"" value=""#ContentKey"">
<input type=""hidden"" id=""RatingId"" value=""RatingId"">
<script type=""text/javascript"">
$(document).ready(function () {
var protocol = location.protocol;
var host = window.location.host;
if ($(""#HasRated"").val() == """"True"")
{
var rate = $(""#Rate"").val();
if (rate == 1) {
setPositiveRatedView();
}
else if (rate == 0) {
setNeutralRatedView();
}
else if (rate == -1) {
setNegativeRatedView();
}
else {
setNotRatedView();
}
}
else {
setNotRatedView();
}
$(""#likeIcon"").click(function () {
alert(""like"");
setPositiveRatedView();
ratePage(1, """");
});
$(""#neutralIcon"").click(function () {
alert(""neutral"");
setNeutralRatedView();
ratePage(0, """");
});
$(""#unlikeIcon"").click(function () {
alert(""unlike"");
setNegativeRatedView();
//mkMPopClc('NegativeRatingReason', 200, 300, 0, 0);
});
$("".updateRate"").click(function () {
setNotRatedView();
});
// $('.clsStl').click(function () {
// ratePage(-1, """");
// $('.mkMPop').fadeOut();
// });
//
// $('#ShareComment').click(function () {
// ratePage(-1, $(""#Comment"").val());
// $('.mkMPop').fadeOut();
// });
function setNotRatedView() {
$(""#divNeutralRating"").fadeOut();
$(""#divPositiveRating"").fadeOut();
$(""#divAskForRating"").fadeIn();
$(""#divNegativeRating"").fadeOut();
}
function setPositiveRatedView()
{
$(""#divNegativeRating"").fadeOut();
$(""#divNeutralRating"").fadeOut();
$(""#divAskForRating"").fadeOut();
$(""#divPositiveRating"").fadeIn();
}
function setNegativeRatedView() {
$(""#divNeutralRating"").fadeOut();
$(""#divPositiveRating"").fadeOut();
$(""#divAskForRating"").fadeOut();
$(""#divNegativeRating"").fadeIn();
}
function setNeutralRatedView() {
$(""#divNegativeRating"").fadeOut();
$(""#divPositiveRating"").fadeOut();
$(""#divAskForRating"").fadeOut();
$(""#divNeutralRating"").fadeIn();
}
function ratePage(rating, comment)
{
//alert(rating + """" """" + comment);
var contentKey = $(""#ContentKey"").val();
var hasRated = $(""#HasRated"").val();
var ratingId = $(""#RatingId"").val();
$.getJSON(protocol + '//' + host + '/tr/Rating/RatePage?contentKey=' + contentKey + '&rating=' + rating + '&ratingUpdate=' + hasRated + '&ratingId=' + ratingId + '&comment=' + comment, function (data) {
$(""#HasRated"").val(data.HasRated);
$(""#Rate"").val(data.Rate);
$(""#ContentKey"").val(data.ContentKey);
$(""#RatingId"").val(data.RatingId);
$(""#Comment"").val(data.Comment);
});
}
});
</script>
</div>");
builder.Replace("#ContentKey", this.ContentKey);
output.Write(builder);
}
}
When I add my control to my web page, I see that control is rendering as I am expecting but the jquery scripts doesn't work. Is it wrong to keep scripting code in a server control? What can I do to solve this problem?
if ($(""#HasRated"").val() == """"True"")
I think you have too many quote characters there...