Adding Hyperlinks to ValidationSummary using programatically added validators - javascript

I'm using the javascript from the answer in this question in a project of mine:
Adding Hyperlinks to ValidationSummary
It works really great. I've added it to the bottom of my masterpage (for some reason, even though it is inside $(document).ready, Page_Validators is null if i place it in the head section)
Anyway! I'm also adding some custom validators programatically on postback using this code:
public static CustomValidator ReturnErrorMessage(string message, string validationGroup, string controlToValidate = "")
{
CustomValidator control = new CustomValidator();
control.ID = "cv" + controlToValidate;
control.IsValid = false;
control.Text = " ";
control.ValidationGroup = validationGroup;
control.ErrorMessage = message;
control.ControlToValidate = controlToValidate;
return control;
}
However whenever I add a CustomValidator like that, in a button event, page_load or whatever, Page_Validators will be overridden and the errormessage will revert to the message without a anchor.
What gives? Am I doing something wrong or can someone explain what is happening?
I've tried debugging it and it does set the values correctly, but then it just reset afterwards.
I've tried for the heck of it and in $(document).ready set all validators as isvalid = false, and that gets overwritten too.
Im using asp.net 4.5 unobtrusive validation, but it does not make a difference if I turn it off.
Adding the javascript in code using Page.ClientScript.RegisterStartupScript at some point after the validator has been created does not work either.
If I don't add any validators in code everything works as expected.
I'm aware I can just add the anchor tags manually, but this is a lot of work to update existing validators instead of just tossing in a small script, so I'm hoping to get this to work.
You can use this code to test this:
using System;
using System.Web.UI.WebControls;
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
CustomValidator control = new CustomValidator();
control.ID = "cv" + txtName.ClientID;
control.IsValid = false;
control.Text = " ";
control.ValidationGroup = "errorGroup";
control.ErrorMessage = "Error message";
control.ControlToValidate = txtName.ClientID;
Form.Controls.Add(control);
}
}
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="jquery-3.3.1.min.js"></script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txtName" runat="server"></asp:TextBox>
<asp:ValidationSummary ID="vsSummary" runat="server" ValidationGroup="errorGroup" ForeColor="Red" HeaderText="Error!" />
</div>
</form>
<script>
$(document).ready(function() {
var validators = Page_Validators; // returns collection of validators on page
$(validators).each(function() {
//get target control and current error validation message from each validator
//[0] is needed when using aspnet 4.5 unobtrusive validation
var validator = $(this)[0];
var errorMsg = validator.errormessage;
var targetControl = validator.controltovalidate;
//make link only if theres a control to target
if (targetControl) {
var errorMsgWithLink = "<a href='#" + targetControl + "' style='color: #FF3232;'> " + errorMsg + "</a>";
//update error message with anchor tag
validator.errormessage = errorMsgWithLink;
}
});
});
</script>
</body>
</html>

If you want you can try implementing your own 'CustomValidationSummary' control by following the same design pattern as mentioned at Reference Source by Microsoft, and modify the render method to include anchor tag to wrap error text, before it is passed into the writer method at line number 462.

I ended up using a extension method, adding the anchor tag in the method
public static void AddValidator(this Page p, string message, string validationGroup, string controlToValidate = "", bool addAnchorTags = true)
{
CustomValidator control = new CustomValidator();
control.ID = "cv" + controlToValidate;
control.IsValid = false;
control.Text = " ";
control.ValidationGroup = validationGroup;
control.ControlToValidate = controlToValidate;
if (addAnchorTags && !string.IsNullOrEmpty(controlToValidate))
{
control.ErrorMessage = "<a href='#" + controlToValidate + "' style='color: #FF3232;'> " + message + "</a>";
}
else
{
control.ErrorMessage = message;
}
p.Validators.Add(control);
}

Related

How do I display an image saved within a file location in a new window by clicking a gridview link? A Terms Popup (modal) should display in between

Ok for a couple of weeks I have been stuck on a problem with one of my branches legacy applications.
I have a gridview and when I click on a link in the gridview I get a relevant image displayed within a new window. A new requirement has come in requesting that after clicking on the new window, the user should be displayed a "Terms of Use" pop up which they need to agree. After agreeing, the image should load in the new window as before.
I tried creating a popup with a modal.dialog using a bit of jquery and a div and I can get this to show. However any attempt I have made to open the image from this pop up has not worked. I think the index of the gridview gets lost when displaying the modal pop up.
The application is about 12 years old (waaaay before me). It was developed in c# and asp.net web forms.
I am new to stack. Apologies about formatting. The filestream code was in there for ages. Would there be a better way of doing this? Thank you for any help in advance.
So the user clicks on link within gridview -> A pop up displays the terms with an Agree button and ideally a cancel button too. User agrees and the popup displays image.
'''<%--button in gridview.--%>
<asp:LinkButton ID="btnOpenObject" runat="server" Text="View" OnClick="OpenObjectSelect_Click"
AlternateText="Opens Object in a new window" OnClientClick="aspnetForm.target= '_blank';" ToolTip="Opens in a new window"
CssClass="btnHyperLinkEnabled">
</asp:LinkButton>
'''<%--modal pop up.--%>
<div id="ModalMessage" title="testWindow" class="divAcceptWindow" style="display: none;">
<label style="font-weight: bold" class="boldCentral">Copying and Copyright Declaration</label>
<br />
This declaration has been issued under rule 5(3).
I declare that: blah blah…
<input type="button" id="okButton" value="I Agree" name="okButton" />
</div>
<script type="text/javascript">
//script to call popup
function showdialog() {
$("#ModalMessage").dialog({ modal: true });
$("#ModalMessage").dialog({ width: 500 });
$(".ui-dialog-titlebar").hide();
scrollTo(0, 0);
}
//script to show image from serverside
$('#okButton').click(function () {
$('#ModalMessage').dialog('close');
var dataToSend = { MethodName: 'IAgree' };
var options =
{
data: dataToSend,
dataType: 'JSON',
type: 'POST',
}
$.ajax(options);
});
</script>
'''//c# (code behind)
'''//Gridview link button click event
protected void OpenObjectSelect_Click(object sender, EventArgs e)
{
LinkButton b = (LinkButton)sender;
int miIndex = Convert.ToInt32(b.CommandArgument);
LocalSearch.DetailPosition = miIndex;
miArchiveItemId = LocalSearch.ArchiveItems[LocalSearch.DetailPosition].ArchiveItemId;
//call popup
this.Page.ClientScript.RegisterStartupScript(this.GetType(), "CallMyFunction", "showdialog()", true);
}
protected void Page_Load(object sender, System.EventArgs e)
{
//hook of jquery button click with method. This is hit after clicking I agree on pop up.
if (!Page.IsPostBack) {
if (Request.Form["MethodName"] == "IAgree") // same Method Name that we are specifying on client side
{
Agree();
return;
}
}
}
'''// Get information relating to image to pass to file stream
private void Agree()
{
ArchiveItem myArchiveItem = new ArchiveItem();
miArchiveItemId = Trunks;
if (miArchiveItemId > 0)
{
//Retrieve data from DB.
myArchiveItem = mysearchMediator.GetArchiveItemByID(miArchiveItemId);
}
DigitalObjectLink(myArchiveItem);
}
//Display the image using a file stream.
//Code works to display image without the file modal
public void DigitalObjectLink(ArchiveItem myArchiveItem)
{
LinkButton OpenObject = new LinkButton();
for (int i = 0; i < GridView1.Rows.Count; i++)
{
OpenObject = (LinkButton)GridView1.Rows[0].FindControl("btnOpenObject");
OpenObject.OnClientClick = "aspnetForm.target ='_blank';";
}
try
{
string path = ConfigurationManager.AppSettings["ImageFilePath"] + '\\' + myArchiveItem.RelativeFolderPath +
'\\' + myArchiveItem.FileName;
//string path = "C:" + '\\' + "Temp" + '\\' + myArchiveItem.FileName;
FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
byte[] ar = new byte[(int)fs.Length];
Response.AddHeader("content-disposition", "attachment;filename=" + myArchiveItem.FileName);
Response.ContentType = "application/octectstream";
ClientScript.RegisterStartupScript(GetType(), "Javascript", "javascript:showdialog('" + path + "'); ", true);
fs.Read(ar, 0, (int)fs.Length);
fs.Close();
Response.BinaryWrite(ar);
Response.Flush();
Response.End();
}
catch
{
/*
** Hide Navigation & GridView & Show File Not Found Panel
*/
OpenObject.OnClientClick = "aspnetForm.target ='_self';";
this.NavigationControl1.Visible = false;
this.NavigationControl2.Visible = false;
this.GridView1.Visible = false;
lblFileNotFound.CssClass = "SearchResultsCount";
btnContactUs.Text = "Please contact PRONI quoting reference: " + myArchiveItem.Reference;
}
}

Async Javascript callback not triggering the RaiseCallBackEvent function

In my asp.net application I used the async javascript callback.
The requirement is once the user enters the Postal code an async javascript callback function should be called. And the server side code must return me the city with respect to the postal code.
The coding I did is:
<asp:TextBox ID="txtPostCode" runat="server" CssClass="textbox" onchange="javascript: getCityAndStreet();" BorderStyle="Ridge" Height="20px" style="margin-left: 10px" Width="442px"></asp:TextBox>
This textbox onchange it will call the javascript function getCityAndStreet()
function getCityAndStreet()
{
var postalCode = document.getElementById('<%=txtPostCode.ClientID%>');
CallServer(postalCode.value, "");
}
function ReceiveCityAndStreet(rValue,context)
{
alert(rValue);
var city = document.getElementById('<%= txtCity.ClientID%>');
city.value = rValue;
}
Here the CallServer is the server side runtime javascript which is registered as below
protected void Page_Init(object sender, EventArgs e)
{
String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveCityAndStreet", "context",true);
String callbackScript;
callbackScript = "function CallServer(arg, context)" + "{ " + "alert('Entered inside CallServer' + arg);" + cbReference + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CallServer", callbackScript, true);
}
I implemented the ICallBackHandler and by this I got 2 methods:
string ICallbackEventHandler.GetCallbackResult()
{
return cityAndStreet;
}
void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)
{
txtStreet.Enabled = true;
txtCity.Enabled = true;
cityAndStreet = eventArgument;
}
in page_load function I just disabled the txtStreet.Enabled. txtCity.Enabled text boxes and on the raise callbackevent I am enabling it.
The issue here is the RaiseCallBackEvent is not working. I mean its not been triggered implicitly.
(This application is not accessed directly in the browser it is accessed through the SharePoint site)
I think the problem is that your button actually does postback when you click on it. You do not need postback because you are calling server using AJAX. Try changing onchage handler to this:
onchange="getCityAndStreet();return false;"
This will cause your button not to trigger postback.
EDIT: Also i want to mention that you cannot change controls in RaiseCallBackEvent method. It is not an actual postback. You need to enable text fields using javascript in onSuccess method.

After another page is loaded in a div, no control is working, giving error

I'm using div instead of iframe to call a page but as soon as the other page loads in div then after clicking on any button, or selecting radiobutton, these events give this error
This is how I load div
<script type="text/javascript">
$(function () {
setInterval(function () {
$('#result').load('frmChatRequest.aspx', function () {
});
}, 10000);
});
</script>
This is frmChatRequest.aspx.cs page
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dt_chatRequest = LookupChat.getPendingRequestInMyChat("",Int64.Parse(_objSession.LoginID), _objSession, _errMsg);
ClsDataBind.DoGridViewBind(gdvChatRequestRoom, dt_chatRequest, _errMsg);
myMarqueeChatRequest.InnerText = "You Have " + dt_chatRequest.Rows.Count.ToString() + " new chat request/s in your rooms in last 15 minutes";
}
}
protected void gdvChatRequestRoom_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Accept")
{
HiddenField hdn = ((HiddenField)gdvChatRequestRoom.Rows[0].Cells[0].FindControl("hdnAddPeople"));
string strHdnValue = hdn.Value;
//Button btn = ((Button)gdvChatRequestRoom.Rows[0].Cells[3].FindControl("btnAccept"));
//string strBtnID = btn.ID;
string strBtnID = e.CommandArgument.ToString();
string query = "select * from Q116 where Q116002="+strBtnID+ " and Q116001="+ hdn.Value ;
_objQ116.SelectAll(query);
_objQ116.Q116DF2 = _objSession.LoginID;
_objQ116.Update(_objQ116.Q116DF2);
_objQ116.SelectAll(query);
_objQ116.Q116004 = DateTime.Now.ToString("hh:mm:ss");
_objQ116.Update(_objQ116.Q116004);
//insert in Q119
// _objQ116.Update(Q116004);
//_objLOG2.SelectAll(query);
//DateTime dt1 = DateTime.UtcNow.AddHours(5.5);
//string str = dt1.ToString();
//_objLOG2.Update(str);
//Write code to add to card
}
if (e.CommandName == "Reject")
{
HiddenField hdn = ((HiddenField)gdvChatRequestRoom.Rows[0].Cells[0].FindControl("hdnAddPeople"));
string strHdnValue = hdn.Value;
//Button btn = ((Button)gdvChatRequestRoom.Rows[0].Cells[3].FindControl("btnAccept"));
//string strBtnID = btn.ID;
string strBtnID = e.CommandArgument.ToString();
string query = "delete from Q116 where Q116001=" + hdn.Value + " and Q116002=" + "'" + strBtnID + "'";
// _objQ116.SelectAll(query);
Educity.EduDB.Select(query);
//Write code to add to card
}
Response.Redirect(Request.Url.AbsolutePath);
}
The ASP.NET webforms JavaScript and markup is probably messing up the hosting page and this is why a whole page is normally loaded in an iframe.
Have you considered using custom controls? They are really easy and encapsulate functionality into objects that can be included in any web page. It looks like frmChatRequest would be better as a control. Building a custom control is very similar to building a aspx webforms page, but it can then be re-used.
For more info on custom controls see http://msdn.microsoft.com/en-us/library/zt27tfhy.ASPX

Call to ClientScript doesnot preserve value in Controls of Web Page

I have a small problem . If page is refreshed using F5 , TextBox should preserve its old value . In Page_Load() , if i keep // Loading(); then TextBox1 preserve its old value.
As soon as i remove comment , it loose value in TextBox1 .
Please tell me the reason behind it and What should be done to avoid it .
<script type="text/javascript">
function TextBox1_TextChanged() {
<%
Session["HitCount1"] = TextBox1.Text ;
%>
}
function getMyvalSession() {
var ff = "Loading Value";
return ff;
}
</script>
<body>
<form id="form1" runat="server">
<asp:TextBox ID="TextBox1" Name="TextBox1" runat="server"
AutoPostBack='true' onchange="TextBox1_TextChanged()"></asp:TextBox>
<%
string x = null;
x = Session["HitCount1"].ToString().Trim();
if ((x.Equals(null)) || (x.Equals("")))
{
// Session Variable is either empty or null .
}
else
{
TextBox1.Text = Session["HitCount1"].ToString();
}
%>
</form>
</body>
protected void Page_Load(object sender, EventArgs e)
{
// Loading();
}
void Loading()
{
String csname = "OnSubmitScript";
Type cstype = this.GetType();
// Get a ClientScriptManager reference from the Page class.
ClientScriptManager cs = Page.ClientScript;
// Check to see if the OnSubmit statement is already registered.
if (!cs.IsOnSubmitStatementRegistered(cstype, csname))
{
string cstext = " document.getElementById(\"TextBox1\").value = getMyvalSession() ; ";
cs.RegisterOnSubmitStatement(cstype, csname, cstext);
}
}
Combining inline server-side code and code-behind code is generally a bad idea. I would recommend just using the code-behind code.
This code:
function TextBox1_TextChanged() {
<%
Session["HitCount1"] = TextBox1.Text ;
%>
}
... is not going to have the effect of the (server-side) Session entry "HitCount1" getting set to Textbox1.Text, because TextBox1_TextChanged is a client-side function, and your assignment statement is going to happen on the server side. At run time, the chunk of server code will have been removed by the compiler, so TextBox1_TextChanged will be an empty function.
The rule of thumb: Things happen on the client, or they happen on the server on postback, or they happen on the server via Ajax calls. You can't mix client and server code together.
My recommendation: switch to doing everything in code-behind. When you have it working, if you have too many postbacks, investigate Ajax calls.

getElementByID() for web user control not working?

I have made a web user control (.ascx) which consists of the two html textbox and two input buttons, when I try to do document.getElementById('<%=ControlID.ClientID%>') it returns null. what could i have done wrong ?
source code:
<script language="javascript" type="text/javascript">
function intilize() {
var x = document.getElementById('<%=JSNumeric_Control.ClientID%>');
}
</script>
<table class="style1">
<tr>
<td >
<My:UserInfoBoxControl ID="JSNumeric_Control" runat="server" />
</td>
<td>
</td>
</tr>
<tr>
<td colspan="2" style="text-align: center">
<input id="Button1" type="button" value="button" onclick="intilize()" /><br />
</td>
</tr>
</table>
Here is the code for the Numbric.cs, the following are the property used and in page load i am using JavaScript to assign all the events for the HTML inputs:
public partial class NumricCounter : System.Web.UI.UserControl
{
public string defualtValue = "0";
public double defaultIncrementValue = 1;
public int defaultPrecsionValue = 0;
public string Button_Add_ClientID
{
get { return Button_Add.ClientID; }
}
public string Button_Subtract_ClientID
{
get { return Button_Subtract.ClientID; }
}
//Set and Get for all these properties. (Code Omitted)
public string Text;
public double IncrementValue;
public int PrecsionValue;
public void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Text_Output.Value = this.Text;
Button_Add.Attributes.Add("onclick", "Add(" + IncrementValue.ToString() + "," + PrecsionValue.ToString() + ");");
Button_Subtract.Attributes.Add("onclick", "Subtract(" + this.IncrementValue.ToString() + "," + this.PrecsionValue.ToString() + ")");
Text_Output.Attributes.Add("onkeyup", "check(" + this.PrecsionValue.ToString() + ");");
}
}
}
Try replacing your function:
function intilize() {
var x = document.getElementById('<%=JSNumeric_Control.ClientID%>');
}
with this:
function intilize() {
var x = document.getElementById('JSNumeric_Control');
}
The getElementById should read the ID of the element from the rendored html.
JSNumeric_Control.ClientID will return the ClientID of the control if it were rendered to the page. It's existance doesn't necessarily mean that there will be HTML on the final page that has that ID.
For example if you create a control that just outputs two buttons you will give each of those buttons different IDs that are not the same as the control that they live in. Often you might create a container div that you will put around all other content which you will give the ID of the Control to for easy finding but there is no reason for this to exist.
What you should do is either make sure that your control does create this HTML container with the ID of your control or you should refer specifically to the client ID of the items inside your control.
var button1 = document.getElementById('<%=JSNumeric_Control.Button1.ClientID%>');
The problem is that in the DOM there's no element with Id = ClientID of your UserInfoBoxControl. The controls inside your user control will have other Ids, like 'JSNumeric_Control_Button1', 'JSNumeric_Control_TextBox1' etc. If you need to get both of the input buttons, you can do one of the following:
Use jquery selector to find all inputs with type = button and id starting with <%=JSNumeric_Control.ClientID%>
Add two new properties to your control - FirstButtonClientID and SecondButtonClientID that will provide you with clientIDs of your buttons. Then you can use it in javascript.
Create custom javascript object which will represent your usercontrol and provide necessary functionality.
You are most likely trying to search the DOM before it's been loaded. Try putting your code inside an onload handler:
document.onload = function () {
alert(document.getElementById('<%=ControlID.ClientID%>'));
}
This makes sure that the code isn't executed before you actually have all of the DOM loaded.
//Button_Add is the control id inside the user control
var x = document.getElementByID(JSNumeric_Control.FindControl("Button_Add").ClientID);

Categories