ASP.NET: How to access repeater generated elements from javascript? - asp.net

i have a series of rows that are generated using an asp:repeater:
<asp:repeater ID="itemsRepeater"
OnItemDataBound="itemsRepeater_ItemDataBound"
runat="Server">
<itemtemplate>
<tr>
<td>
<asp:HyperLink ID="linkView" runat="server"
Text="<%# GetItemText((Item)Container.DataItem) %>"
NavigateUrl="<%# GetViewItemUrl((Item)Container.DataItem) %>" />
</td>
<td>
<asp:HyperLink ID="linkDelete" runat="server"
Text="Delete"
NavigateUrl="<%# GetDeleteUrl((ActionItem)Container.DataItem) %>" />
</td>
</tr>
</itemtemplate>
</asp:repeater>
The repeater creates an HTML table, with each row containing a link to an item and (what is essentially) a "Delete" link. The above simplified example code generates HTML similar to:
<TR>
<TD>
<A href="ViewItem.aspx?ItemGuid={19a149db-5675-4eee-835d-3d78372ca6f9}">
AllisonAngle_SoccerGirl001.jpg
</A>
</TD>
<TD>
Delete
</TD>
</TR>
Now that all works, but i want to convert the "Delete" to client side. i want to be able click the link and it will, on the client javascript:
prompt an alert "Are you sure..."
have javascript issue server-hit to actually delete the item they want
remove the item from the client DOM tree
So there are four problems to be solved:
How to hook up javascript to the client-side click of the Delete link.
How to know what item the user clicked Delete
Prevent a post-back
Delete the row that the user clicked
That is my question.
From here on you will find my rambling attempts to solve it. Don't take anything below as relating in any way to any possible accepted solution. Just because i posted code below, doesn't mean any of it is useful. And it doesn't mean i'm anywhere within spitting distance of the best solution. And because i can't make anything below work - it must have gone down the wrong road.
My Attempts
Wiring Up Javascript
The first task is to convert the delete link HTML from something such as:
<A href="DeleteItem.aspx?ItemGuid={19a149db-5675-4eee-835d-3d78372ca6f9}">
Delete
</A>
into something more javascripty:
<A href="#"
onclick="DeleteItem('DeleteItem.aspx?ItemGuid={19a149db-5675-4eee-835d-3d78372ca6f9}')">
Delete
</A>
and the add the script:
<script type="text/javascript">
//<![CDATA[
function DeleteItem(deleteUrl)
{
//Ask the user if they really want to
if (!confirm("Are you sure you want to delete INSERT NAME HERE?"))
{
return false;
}
//Call returns false if the server returned anything other than OK
if (!DoAjaxHit(deleteUrl)
{
return false;
}
//Remove the table row from the browser
var tableRow = document.getElementById("TODO-WHAT ID");
if (row != null)
{
//TODO: how to delete the tableRow from the DOM tree?
//document.Delete(tableRow) ?
}
//return false to prevent a postback
return false;
}
//]]>
</script>
What combination of ASP code can be used to create the above? i hear that asp:LinkButton has an OnClientClick event, where you can wire up a javascript function:
<asp:LinkButton ID="linkDelete" runat="server"
Text="Delete"
OnClientClick="DeleteItem(<%# GetDeleteUrl((ActionItem)Container.DataItem) %>);"/>
Problem is that the rendered HTML is literally containing:
<a onclick="DeleteItem(<%# GetDeleteUrl((ActionItem)Container.DataItem)) %>);" ...>
Delete
</a>
If i change the client click event handler to:
OnClientClick="DeleteItem('todo - figure this out');"/>
it works - as well as "todo - figure this out" can work.
Preventing Postbacks
The dummied down above javascript call actually happens (i can see my alert), but there's the next problem: Returning false from the javascript function doesn't prevent a postback. In fact, i can see that the href on the generated html code isn't "#", but rather
javascript:__doPostBack('ctl0....
i tried changing the ASPX code to include the OnClick handler myself:
OnClick="#"
OnClientClick="DeleteItem('todo - figure this out');"
But the compiler thinks the pound side is a pragma, and whines:
Preprocessor directives must appear as
the first non-whitespace character on
a line
Table Row Identity
The table rows don't have an ID, they're generated by the asp:repeater.
How can the javascript function know what triggered the click event? The javascript needs to be able to find the element, and remove it from the tree.
Note: i would of course prefer fade+collapse animation.
Normally you get an element by using
var tr = document.getElementById("the table row's id");
But the table rows don't have an easily knowable ID. Since there are multiple rows, the server generates the ID as it builds the table. i realize some solution is going to have to involve changing:
<TR>
into
<TR runat="server">
so that there will be server generated identity for each table row, but how do i reference the generated name from javsscript?
Normally i would have thought that the scripting problem would be solved by using multiple paramters:
function DeleteItem(tableRowElement, deleteUrl)
{
//Do a web-hit of deleteUrl to delete the item
//remove tableRowElement DOM object from the document tree
}
But the problem is just pushed elsewhere: How do you populate tableRowElement and deleteUrl for the call to the javascript function?
Such a simple problem: convert a click from a postback to client-side.
The volume of problems involved is getting quite idiotic. Which seems to indicate that either
the idea solution is something completely different
there is no solution
References
Stackoverflow: How do I fade a row out before postback?
Stackoverflow: Javascript before asp:ButtonField click
asp.net: Accessing repeater elements from javascript.
Stackoverflow: How to access repeater generated elements?

jQuery can dig out the tags for you:
$("[id$=linkDelete]").click(function() {
DeleteItem(this.href);
});
That code says "find all the DOM elements whose ID ends with 'linkDelete' and wire up the following click event handler".

I would recommend against implementing the Delete function through links in this way. Delete links are a security risk.
Rather, it's better to require a post to that url instead. If you want to be doing ajax, I would strongly recommend using a javascript framework so you don't have to deal with the differences in how different browsers implement XmlHttpRequests.
For instance, in jQuery you could do it like this:
$.post('Delete.aspx',{itemGuid:'{19a149db-5675-4eee-835d-3d78372ca6f9}'},
function(data, textStatus) {
if (textStatus == 'success') {
$(this).parents('tr:eq(0)').fadeOut();
}
});
which would do both the ajax call and the fadeout effect you want.
You could then access the item guid in Delete.aspx from Request.Form["itemGuid"], and this wouldn't be vulnerable to link attacks.
Preventing Postbacks
The server is generating a postback wireup because you're using a server control. Use a plain <a> tag without a runat='server' directive.
Table Row Identity
I usually do this by databinding an ID column of some kind and putting this in the repeater template:
<tr id='<%#Eval("ID")%>'>
P.S. I hate to sound like a fanboy, but jQuery will make all of these things an order of magnitude easier. You should really consider it if you can. Otherwise, you're going to be in a world of hurt trying to implement these features in a consistent way across browsers.
P.P.S. If the Delete.aspx and similar urls are only going to be called from javascript, I would recommend using ashx http handlers instead. You can do all of the same server logic without the needless overhead of a full-blown page.

mine usually comes out looking like
<asp:LinkButton runat="server" OnClientClick='<%# Eval("ID", "DeleteItem(this, \"{0}\"); return false;") %>' Text="Delete" />
that will make html that looks like
<a id="blah_blah_ctl01" onclick='DeleteItem(this, "{19a149db-5675-4eee-835d-3d78372ca6f9}"); return false;'>Delete</a>
I include the "this" reference so that you can have access to the dom and delete the link...or it's parent or whatever. From there it's pretty straight forward to use jQuery to actually do the posting and DOM manipulation. The "return false;" disables the postback.

The other answerers found various bits related to different aspects of the question. i managed to cobble together a complete solution. i've copy/pasted the relavent snippits here.
The first important change is the use of an asp:LinkButton which allows as OnClientClick event, which gives you direct access to the javascript OnClick event:
<asp:repeater ID="itemsRepeater"
OnItemDataBound="itemsRepeater_ItemDataBound"
runat="Server">
<itemtemplate>
<tr>
<td>
<asp:HyperLink ID="linkView" runat="server"
Text="<%# GetItemText((Item)Container.DataItem) %>"
NavigateUrl="<%# GetViewItemUrl((Item)Container.DataItem) %>" />
</td>
<td>
<asp:LinkButton ID="linkImpregnate" runat="server"
Text="Impregnate"
OnClientClick="<%# GetImpregnateUrl((Item)Container.DataItem) %>" />
</td>
</tr>
</itemtemplate>
</asp:repeater>
The code-behind manually builds presentation code (yay for separation of controller and view!) that contains a javascript call.
protected string GetNodeAcknowledgementClientClick(Item item)
{
if (!(item is HotGirl))
return ""; //this shouldn't be called for non-acknowledgements, but i won't fail
HotGirl girl = (HotGirl)item;
String szOnClientClick =
"return ImpregnateGirl(this, "+
Toolkit.QuotedStr(girl.GirlGUID.ToString()) + ", "+
Toolkit.QuotedStr(GetItemName(item))+");";
return szOnClientClick;
}
And finally in the aspx, i find a random spot to mash in some javascript:
<script type="text/javascript" src="Javascript/jquery.js"></script>
<script type="text/javascript">
//<![CDATA[
function DeleteItem(sender, girlGuid, girlName)
{
if (!confirm("Are you sure you want to impregnate "+girlName+"?"))
{
return false;
}
$.post(
'ImpregnateGirl.aspx?GirlGUID='+nodeGuid,
function(data, textStatus) {
if (textStatus == 'success')
{
$(sender).parents('tr:eq(0)').hide();
}
else
{
return false;
}
}
);
//return false to suppress the postback
return false;
}
//]]>
</script>
i would have made the jQuery do a post, as a security measure as guy suggested, but jQuery would give an error, rather than posting. Rather than care i chose to not care.

Related

How to pass the textbox id to javascript function in asp.net application

I am developing an application in which I have a asp.net form with a lot of textboxes.I need to use the same JavaScript function for all the textboxes to validate whether it contains any non alphabetic character in it. How can I use the same method for all the textboxes? I am stuck at how could I pass the id of the textbox to the JavaScript function.
<script type="text/javascript" language="JavaScript">
function CheckAlphabet(textboxId)
{
if (!document.getElementById('<%=textboxId.ClientId %>').value.match("/^[a-zA-Z]+/"))
return false;
}
</script>
asp.net code part is like this....
<asp:TextBox CssClass="select" ID="TxtEmpFirstname" onkeydown="CheckAlphabet(TxtEmpFirstname)"
runat="server" MaxLength="100"></asp:TextBox>
The Javascript code gave an error. Please help with passing the id of the asp.net textbox. I need to use the same Javascript function for many textboxes to validate for non alphabet characters in the textbox. Please help.
Right approach would be carefully look at code and see what runs on server and what runs in the browser (i.e. print the code and mark in 2 colors)...
You onkeydown="CheckAlphabet(TxtEmpFirstname)" is mix of server side and client side intentions: you should construct client ID with server side code instead of TxtEmpFirstname and remove it from the function itself.
onkeydown="CheckAlphabet('<%=textboxId.ClientId %>')"
Try this:
function CheckAlphabet(textboxId)
{
if (!textboxId.value.match("/^[a-zA-Z]+/"))
return false;
}
<asp:TextBox CssClass="select" ID="TxtEmpFirstname" onkeydown="javascript:CheckAlphabet(this)" runat="server" MaxLength="100"></asp:TextBox>
You're on the right track. Try something like this:
<script type="text/javascript" language="JavaScript">
function CheckAlphabet(textboxId){
if (!document.getElementById(textboxId).value.match("/^[a-zA-Z]+/")) return false;
}
</script>
<asp:TextBox CssClass="select" ID="TxtEmpFirstname" onkeydown='CheckAlphabet("<%=TxtEmpFirstname.ClientId %>")' runat="server" MaxLength="100"></asp:TextBox>
Notice that the client-side script only references the contents of the variable that is passed to it. When the TextBox is rendered to the page, the inline tag (<%=...%>) will be converted into the client-side ID of the input field.
Also take note of the quote usage. When you put an inline server-side command in the property of a server-side tag, you have to wrap the property with single quotes and then use double quotes to represent literal strings in what will be the final output.
use this:
function CheckAlphabet(textboxId)
{
if (!document.getElementById(textboxId).value.match("/^[a-zA-Z]+/"))
return false;
}
<asp:TextBox CssClass="select" ID="TxtEmpFirstname" onkeydown="CheckAlphabet(this.value)" runat="server" MaxLength="100"></asp:TextBox>
javascript code will be complained after server side codes compiled

Before deleting a row in repeater , i want to do validation asking that, are sure you want to delete..?How can i do this?

i want to do validation asking that, are sure you want to delete..?
<asp:LinkButton ID="lnkDelete" runat="server"
CommandName='<%# DataBinder.Eval(Container.DataItem, "ImageId") %>' OnCommand="Calling_Delete">Delete</asp:LinkButton>
The easiest way to do it is to use Confirm Button extender. Just drag this control next to the linkbutton and set the Confirmbutton externders TargetControlID to the Id of the Linkbutton. Everything else will be taken care of by the control.
More info- http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/ConfirmButton/ConfirmButton.aspx
Use OnClientClick property to attach the java-script that will do the prompting. For example,
<asp:LinkButton ID="lnkDelete" runat="server"
CommandName='<%# DataBinder.Eval(Container.DataItem, "ImageId") %>'
OnClientClick="return confirm('Are sure you want to delete..?');"
OnCommand="Calling_Delete">Delete</asp:LinkButton>
This answer has one way to do it, using jQuery and a jQuery UI dialog
One advantage of using a javascript dialog such as that provided by jQuery UI is that the popup dialog is modal only for the web page on which it is displayed. You can still access other tabs within your browser while the popup is displayed.
Other solutions that use the javascript confirm function will force the user to dismiss the confirmation dialog before switching to another browser tab.
if u'd like to use custom confirmation ( like jquery dialog,bootboxjs etc.. ) then you have to generate button's "postback string" or get it somehow. asp.net gives such as postback name after rendering the page; __doPostBack('ctl00$ContentPlaceHolder1$btnDeleteSelected',''). after realizing this i wrote a js function which is generates button's postback str;
function PostBackBtnMake(id) { // id : ContentPlaceHolder1_btnDeleteSelected
var result;
var temp = id.split('_');
result = 'ctl00$' + temp[0] + '$' + temp[1];
return result;
}
then i be able to use in custom confirmation box (in this case i used bootboxjs);
function PostBackBtn(e) {
var _result = false;
bootbox.confirm("Are you sure?", function (result) {
if (result) {
__doPostBack(PostBackBtnMake(e.id), '')
}
});
return _result;
}
it's worked for me, i hope it helps you too.

How do I pass parameters in window.open method

How do I pass parameters in window.open method.
<table id="tblUsers" cellspacing="0" >
<asp:Repeater ID="repUsers" runat="server">
<ItemTemplate>
<tr><td> <a ID="hlUser" runat="server" Target="_new" onclick="return OpenWindow();" ><%# Eval("Username") %></a></td></tr>
</ItemTemplate>
</asp:Repeater>
</table>
function OpenWindow() {
var toUsername = document.getElementById("hlUser");
window.open("ChatWindow.aspx?username=" + toUsername.value, "ChatWindow", "width=350,height=250");
return null;
}
I don't know much about asp.net, but looks like you have a javascript problem. Isn't document.getElementById("hlUser") an <a> element? It has no value attribute.
If you want to get the text element inside the <a> you could query the text property, or innerHTML.
<a id="hlUser">somevalue</a>
document.getElementById('hlUser').text will return somevalue
UPDATE:
Having that <a> inside a repeater makes it impossible to know with confidence any id attribute inside it beforehand. I'd reccomend passing the <a> element, or this.text itself , or even the value using the same server-side script to the function.
UPDATE 2: I see this question might be a duplicate of How do I pass a variable using window.open()?
Just change the & to a +:
function OpenWindow() {
var toUsername = document.getElementById("hlUser");
window.open("ChatWindow.aspx?username=" + toUsername.value, "ChatWindow", "width=350,height=250");
return null;
}
At this level of code, you're working in Javascript rather than VB, and VB's use of & for concatenation is an oddity among programming languages.

Why I cannot add clientId of my textBox in the mark-up here so that I can find it with jQuery?

Simply I am trying to pass the client Id of one textBox 'txtPersonId' for the client-click event so that I can traverse to that textBox control and pass its jQuery wrapper to the loadePerson() function.
This is how I decalre it in the aspx mark-up:
<asp:Button ID="btnSearch" runat="server" Text="ARA" OnClientClick="loadPerson(jQuery('#<%=txtPersonId.ClientID %>'))"/>
But when I render it, the
<%=txtPersonId.ClientID %>
place holder stays as it is and it is not replaced with the rendered control's client Id.
Any idea why this happens and how should I overcome that?
When I've had issues like this I've resorted to wrapping the entire expression in the brackets and building the result as a string. I assume that it's because the parser doesn't recognize the render block syntax embedded inside the string property.
<asp:Button ID="btnSearch" runat="server" Text="ARA"
OnClientClick='<%= "loadPerson(jQuery(\"#" + txtPersonId.ClientID + "\"))" %>' />
I've long since moved on to keeping my javascript completely separate from my mark up, so I may be a little fuzzy on the exact details. If you wanted to separate your javascript from your mark up you could either add the handler with an explicit or relative DOM reference in a script block. Using the "ends with" selector matching on the id removes the need to find the explicit id, though you could also do that -- the example below shows both styles.
<script type="text/javascript">
$(function() {
$('#' + '<%= btnSearch.ClientID %>').click( function() {
loadPerson( $('input[id$=txtPersonId]') );
});
});
</script>
I don't know what it does your LoadPerson,but if you want write a function for your click event in Jquery you can make something like:
'#'+ '<%=txtPersonId.ClientID %>' to address your txtbox ID you can do the samething for your button $('#' + '<%=btnSearch.ClientID%>').click(function(){//click event process});

Disable backspace in textbox via javascript

I have a textbox which is extended by an Ajax Control Toolkit calendar.
I want to make it so that the user cannot edit the textbox and will have to instead use the calendar extender for input.
I have managed to block all keys except backspace!
This is what I have so far:
<asp:TextBox ID="TextBox1" runat="server" onKeyPress="javascript: return false;" onKeyDown="javascript: return false;" onPaste="javascript: return false;" />
How would I also disable backspace within the textbox using javascript?
EDIT
Made an edit since I need a solution in javascript.
EDIT
It turns out that onKeyDown="javascript: return false;" DOES work. I have no idea why it wasn't working before. I tried using a new textbox and it blocked backspaces fine. So sorry to everyone who posted an answer hoping to get some rep esp. after I marked it for bounty.
My textboxes now (seem) to block ALL keystrokes and also still work with the calendar extender.
ZX12R was close. This is the correct solution:
The TextBox is like this:
<asp:TextBox ID="TextBox1" runat="server" onKeyDown="preventBackspace();"></asp:TextBox>
and the script looks like this:
<script type="text/javascript">
function preventBackspace(e) {
var evt = e || window.event;
if (evt) {
var keyCode = evt.charCode || evt.keyCode;
if (keyCode === 8) {
if (evt.preventDefault) {
evt.preventDefault();
} else {
evt.returnValue = false;
}
}
}
}
</script>
First of all, the backspace wont come through on Key Press, so you have to use Key Down.
Can't you just use the HTML readonly="readonly" attribute?
<input type="text" name="country" value="Norway" readonly="readonly" />
<textarea rows="3" cols="25" readonly="readonly">
It should work! :)
</textarea>
How about using a label for the display and a hidden textbox to get the value back to the server?
You need to apply readonly on the client side controller ONLY, so that asp.net doesn't see it and still reads the data on postback. You can do this several ways, one of the easier if you use jQuery is to add a class to the text-boxes eg. cssclass="readonly" in question and $(".readonly").attr("readonly", true);.
As others said ReadOnly="True" will break the postback mechanism.
I believe you can get around it in your code-behind by accessing the Request object directly during PageLoad:
//assuming your textbox ID is 'txtDate'
if(Page.IsPostBack)
{
this.txtDate.Text = Request[this.txtDate.UniqueID];
}
Your other option is to allow Disabled controls to postback on the form, but this is somewhat of a security concern as readonly fields modified via script could potentially come back:
<form id="MyForm" runat="server" SubmitDisabledControls="True">
..
</form>
http://msdn.microsoft.com/en-us/library/system.web.ui.htmlcontrols.htmlform.submitdisabledcontrols.aspx
I'm not sure the impact of this property on ReadOnly (vs Enabled="False") controls but it's worth trying.
And finally - I did run into the same issue you're having a few years ago, and from what I remember there is a difference between using an html input marked as readonly and runat="server", and an actual serverside control where ReadOnly="true".
I have a feeling doing:
<input type="text" readonly="readonly" runat="server" id="myTextBox" />
may have still allowed the data to come through, although in the code-behind you have to treat the control as a HtmlInputText or HtmlGenericControl vs. a TextBox. You can still access the properties you need though.
Just a few ideas anyway...
here is a possible solution... add an event listener...
<asp:TextBox ID="TextBox1" runat="server" onKeyPress="KeyCheck;" />
and then the function can be like this..
function KeyCheck(e) {
var KeyID = (window.event) ? event.keyCode : e.keyCode;
if (KeyID == 8 ) {
alert('no backspaces!!);
}
}
doubt if it has to be onkeypress or onkeyup...
ReadOnly attribute does not help. The backspace still is taking your browser to back page even if your text box is read only..
use regular text boxes not read-only and not Disabled, just use client-side JavaScript to ignore keypresses.
This will ignore all keypress so you will have your READONLY behaviour and it will also ignore the backspace.
<input type="text" value="Your Text Here" onkeydown="return false;" />
No Need to call any function and all just try this:
<asp:TextBox runat="server" ID="txt" onkeydown="return false;"
onpaste = "return false;" onkeypress="return false;" />
I was able to do something similar, with Jquery. Just putting it out here for reference!
$("#inputID").keypress(function (e)
{e.preventDefault();});
$("#inputID").keydown(function (e)
{e.preventDefault();});
the first prevents keypresses, while the second prevents key down events.
Still a JS noob, so feel free to point out good / bad things with this.

Resources