Developing custom asp.net server control rendering scripting code - c#

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...

Related

How to call c# function in cshtml(razor page) from inside js function

How to call c# function in cshtml(razor page) from inside js function
this is cshtml code
#model TreeWithUnity.Pages.Tree.TreeExampleModel
<form method="post">
<input type="checkbox"
onclick="requestMyAction('#Model.tree_List[0].board_id', this.checked,
'loader-#Model.tree_List[0].dataName',#Model.tree_List[0]);" />
<div class="loader" style="display: none;" id="loader-#Model.tree_List[0].dataName">#Model.tree_List[0]
</div>
</form>
#section scripts{
<script type="text/javascript">
function requestMyAction(itemId, isChecked, loaderId,tn)
{
document.getElementById(loaderId).style.display = "inline-block";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
document.getElementById(loaderId).style.display = "none";
if (this.status === 200) {
document.getElementById(loaderId).style.display = "none";
}
}
};
var url = '#Url.Page("./TreeExample", "MyAction")';
xhr.open('POST', url);
xhr.setRequestHeader('RequestVerificationToken', '#Xsrf.GetAndStoreTokens(Model.HttpContext).RequestToken');
var data = new FormData();
data.append('itemName', itemId);
data.append('deploy', isChecked);
xhr.send(data);
#UpdateRecursiveData(tn)
}
}
</script>
}
#{
void UpdateRecursiveData(TreeWithUnity.Model.TreeNode tn)
{
if(tn.deployment)
{
<input type="checkbox"
onclick="requestMyAction('#tn.board_id', this.checked, 'loader-#tn.dataName');" />
<div class="loader" style="display: none;" id="loader-#tn.dataName">#tn.dataName</div>
<br />
for (int i = 0; i < tn.subTreeNodes.Count; i++)
RecursiveData(tn.subTreeNodes[i]);
}
}
}
#UpdateRecursiveData(tn) is not work
is it able to work in js c#func ?
I don't know how to implement this
UpdateRecursiveData should be executed later than MyAction of Tree Example. Is this possible?
how to call UpdateRecursiveData
public async Task<IActionResult> OnPostMyAction(string itemName,bool deploy)
{
if (TempData["TreeData"] != null)
tree_List = TempData.Get<List<TreeNode>>("TreeData");
TreeNode upTree=null;
foreach (var item in tree_List)
{
if (item.board_id == itemName)
{
upTree = item;
item.deployment = deploy;
}
}
if (deploy&&upTree.loadOn==false)
{
if(upTree!=null)
upTree.deployment = true;
IQueryable<tbl_tree> iqueryTree;
iqueryTree = _context.tbl_tree.Where(x => x.upcode == itemName);
var datas =await iqueryTree.ToListAsync();
for (int i = 0; i < datas.Count; i++)
{
TreeNode treeNode = new TreeNode(datas[i].name);
treeNode.board_id = datas[i].icd11;
tree_List.Add(treeNode);
}
TempData.Set("TreeData", tree_List);
}
return new OkResult();
}
Firstly,you cannot pass a js variable to c# function,you can try to use ajax to call c# handler,and handler returns html code,then put the html code to somewhere of the view.Here is a demo:
<form method="post">
</form>
<div id="data"></div>
#section scripts{
<script type="text/javascript">
$(function () {
$.ajax({
type: "POST",
url: '?handler=UpdateRecursiveData',
headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() },
data: {id:1},
success: function (data) {
document.getElementById("data").innerHTML = data;
},
error: function (result) {
alert("fail");
}
})
})
</script>
}
handler:
public JsonResult OnPostUpdateRecursiveData(int id)
{
return new JsonResult("<div>id="+id+"</div>");
}
result:

ASP.NET Core 2 - Default number input validation is overriding my custom client validation

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.

DataTable equivalent in Jquery to store data?

I have a form on which I am adding rows dynamically using Jquery.
Please take a look: DEMO
Now I want to save the data of all rows that has been added in my database using Jquery Ajax call on click event of SAVE button. The point where I am stuck is .. I am not sure how should I extract data of all rows and send it to the webmethod. I mean had it been c# I could have used a DataTable to store data of all rows before sending it to DataBase. I think I should create a string seperated by commas and pipe with data of each row and send it to webmethod. I am not sure if its the right approach and also how this is to be done (ie. creating such a string).
HTML
<table id="field">
<tbody>
<tr id="row1" class="row">
<td> <span class='num'>1</span></td>
<td><input type="text" /></td>
<td><select class="myDropDownLisTId"> <input type="text" class="datepicker" /></select></td><td>
<input type="submit"></input>
</td>
</tr>
</tbody>
</table>
<button type="button" id="addField">Add Field</button>
<button type="button" id="deleteField">Delete Field</button>
<button type="button" id="btnsave">SAVE</button>
2 suggestions:
To keep it as close as what you already have, you could just enclose your table in a form tag, and then you could just submit the form (use something like the jQuery Form plugin to submit it via Ajax). The trickiest part will be to bind that data to action parameters. You may be able to receive it in the form of an array, or you could default to looping through properties of the Request.Form variable. Make sure you generate proper names for those fields.
I think the cleanest way to do it would be to have a JavaScript object holding your values, and having the table generated from that object, with 2-way bindings. Something like KnockoutJS would suit your needs. That way the user enters the data in the table and you'll have it ready to be Json-serialized and sent to the server. Here's a quick example I made.
I wouldn't recommend that approach, but if you wanted to create your own string, you could do something along those lines:
$("#btnsave").click(function () {
var result = "";
$("#field tr").each(function (iRow, row) {
$("td input", row).each(function (iField, field) {
result += $(field).val() + ",";
});
result = result + "|";
});
alert(result);
});
You will have problems if the users types in a comma. That why we use well known serialization formats.
use ajax call on save button event...
like this
$(document).ready(function () {
$('#reqinfo').click(function () {
// debugger;
var emailto = document.getElementById("emailid").value;
if (emailto != "") {
$.ajax({
type: "GET",
url: "/EmailService1.svc/EmailService1/emaildata?Email=" + emailto,
// data: dat,
Accept: 'application/json',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
// debugger;
},
error: function (result) {
// debugger;
}
});
}
else {
//your validation message goes here
return false;
}
});
});
and add you all data in quesry string and transfer it to webservice..
url: "/EmailService1.svc/EmailService1/emaildata?Email=" + emailto + "data1=" + data1,
<script type="text/javascript">
var _autoComplCounter = 0;
function initialize3(_id) {
var input_TO = document.getElementById(_id);
var options2 = { componentRestrictions: { country: 'ID' } };
new google.maps.places.Autocomplete(input_TO, options2);
}
google.maps.event.addDomListener(window, 'load', initialize3);
function incrementValue() {
var value = parseInt(document.getElementById('number').value, 10);
value = isNaN(value) ? 0 : value;
value++;
document.getElementById('number').value = value;
}
function GetDynamicTextBox(value) {
var _id = "AutoCompl" + _autoComplCounter;
_autoComplCounter++;
return '<input name = "DynamicTextBox" type="text" id="' + _id + '" value = "' + value + '" onkeypress = "calcRoute();" />' +
'<input type="button" class="superbutton orange" value="Remove" onclick = "RemoveTextBox(this)" />'
}
function AddTextBox() {
var value = parseInt(document.getElementById('number').value, 10);
value = isNaN(value) ? 0 : value;
value++;
if (document.getElementById('number').value < 3) {
document.getElementById('number').value = value;
var div = document.createElement('DIV');
var _id = "AutoCompl" + _autoComplCounter;
_autoComplCounter++;
var ht = '<input name = "DynamicTextBox" type="text" id="' + _id + '" value = "" onkeypress = "calcRoute();" class="clsgetids" for-action="' + _id + '" />' +
'<input type="button" class="superbutton orange" value="#Resources.SearchOfferRides.btnRemove" onclick = "RemoveTextBox(this); calcRoute();" />';
div.innerHTML = ht;
document.getElementById("TextBoxContainer").appendChild(div);
setTimeout(function () {
var input_TO = document.getElementById(_id);
var options2 = { componentRestrictions: { country: 'ID' } };
new google.maps.places.Autocomplete(input_TO, options2);
}, 100);
document.getElementById("TextBoxContainer").appendChild(div);
}
else {
alert('Enter only 3 stop point. !!');
}
}
function RemoveTextBox(div) {
//calcStopPointRoute();
var value = parseInt(document.getElementById('number').value, 10);
value = isNaN(value) ? 0 : value;
value--;
document.getElementById('number').value = value;
document.getElementById("TextBoxContainer").removeChild(div.parentNode);
}
function RecreateDynamicTextboxes() {
var values = eval('<%=Values%>');
if (values != null) {
var html = "";
for (var i = 0; i < values.length; i++) {
html += "<div>" + GetDynamicTextBox(values[i]) + "</div>";
}
document.getElementById("TextBoxContainer").innerHTML = html;
}
}
// window.onload = RecreateDynamicTextboxes;
</script>
And get the value from textbox:
#region stop point
string[] textboxValues = Request.Form.GetValues("DynamicTextBox");
if (textboxValues != null)
{
for (Int32 i = 0; i < textboxValues.Length; i++)
{
if (textboxValues.Length == 1)
{
model.OptionalRoot = textboxValues[0].ToString();
}
else if (textboxValues.Length == 2)
{
model.OptionalRoot = textboxValues[0].ToString();
model.OptionalRoot2 = textboxValues[1].ToString();
}
else if (textboxValues.Length == 3)
{
model.OptionalRoot = textboxValues[0].ToString();
model.OptionalRoot2 = textboxValues[1].ToString();
model.OptionalRoot3 = textboxValues[2].ToString();
}
else
{
model.OptionalRoot = "";
model.OptionalRoot2 = "";
model.OptionalRoot3 = "";
}
}
}
#endregion
Short answer:
DataTable equivalent in javascript is Array of custom object (not exact equivalent but we can say that)
or
you roll your own DataTable js class which will have all the functions and properties supported by DataTable class in .NET
Long answer:
on client side(aspx)
you define a class MyClass and store all your values in array of objects of that class
and then pass that array after stingyfying it to web method
JSON.stringify(myArray);
on the server side(codebehind)
you just define the web method to accept a list of objects List<MyClass>
PS: When calling web method, Asp.net automatically converts json array into List<Object> or Object[]
Loooong answer (WHOLE Solution)
Page aspx:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<link href="App_Themes/SeaBlue/jquery-ui-1.9.2.custom.css" rel="stylesheet" type="text/css" />
<script src="Scripts/jquery-1.8.3.js" type="text/javascript"></script>
<script src="Scripts/jquery-ui-1.9.2.custom.min.js" type="text/javascript"></script>
<script src="Scripts/json2.js" type="text/javascript"></script>
<script type="text/javascript">
function MyClass(title,option,date) {
this.Title = title;
this.Option = option;
this.Date = date;
}
function GetJsonData() {
var myCollection = new Array();
$(".row").each(function () {
var curRow = $(this);
var title = curRow.find(".title").val();
var option = curRow.find(".myDropDownLisTId").val();
var date = curRow.find(".datepicker").val();
var myObj = new MyClass(title, option, date);
myCollection.push(myObj);
});
return JSON.stringify(myCollection);
}
function SubmitData() {
var data = GetJsonData();
$.ajax({
url: "testForm.aspx/PostData",
data: "{ 'myCollection': " + data + " }",
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
success: function () {
alert("Success");
}
});
}
$(document).ready(function () {
filldd();
CreateDP();
var rowstring = "<tr class='row'><td class='number'></td><td><input type='text' class='title'/></td><td><select class='myDropDownLisTId'/><input type='text' class='datepicker'/></td><td><input type='submit'></input></td></tr>";
$("#addField").click(function (event) {
$("#field tbody").append(rowstring);
filldd();
CreateDP();
if ($("td").hasClass("number")) {
var i = parseInt($(".num:last").text()) + 1;
$('.row').last().attr("id", "row" + i);
$($("<span class='num'> " + i + " </span>")).appendTo($(".number")).closest("td").removeClass('number');
}
event.preventDefault();
});
$("#deleteField").click(function (event) {
var lengthRow = $("#field tbody tr").length;
if (lengthRow > 1)
$("#field tbody tr:last").remove();
event.preventDefault();
});
$("#btnsave").click(function () {
SubmitData();
});
});
function filldd() {
var data = [
{ id: '0', name: 'test 0' },
{ id: '1', name: 'test 1' },
{ id: '2', name: 'test 2' },
{ id: '3', name: 'test 3' },
{ id: '4', name: 'test 4' },
];
for (i = 0; i < data.length; i++) {
$(".myDropDownLisTId").last().append(
$('<option />', {
'value': data[i].id,
'name': data[i].name,
'text': data[i].name
})
);
}
}
function CreateDP() {
$(".datepicker").last().datepicker();
}
$(document).on('click', 'input[type="submit"]', function () {
alert($(this).closest('tr')[0].sectionRowIndex);
alert($(this).closest('tr').find('.myDropDownLisTId').val());
});
</script>
</head>
<body>
<form id="frmMain" runat="server">
<table id="field">
<tbody>
<tr id="row1" class="row">
<td>
<span class='num'>1</span>
</td>
<td>
<input type="text" class="title"/>
</td>
<td>
<select class="myDropDownLisTId">
</select>
<input type="text" class="datepicker" />
</td>
<td>
<input type="submit"></input>
</td>
</tr>
</tbody>
</table>
<button type="button" id="addField">
Add Field</button>
<button type="button" id="deleteField">
Delete Field</button>
<button type="button" id="btnsave">
SAVE</button>
</form>
</body>
</html>
CodeBehind:
public partial class testForm : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[WebMethod]
public static void PostData(List<MyClass> myCollection)
{
Console.WriteLine(myCollection.Count);
}
}
public class MyClass
{
string title;
public string Title
{
get { return title; }
set { title = value; }
}
string option;
public string Option
{
get { return option; }
set { option = value; }
}
string date;
public string Date
{
get { return date; }
set { date = value; }
}
}
Hope this helps
References:
Json2.js file
stringify method
define a class in js

after call ajax from jquery menu action view mvc c# is not rendering _layout

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)
}
});

Handling events in asp.net server control

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.

Categories

Resources