The "this" in javascript and ASP.NET control prefixes - asp.net

I have code that renders the following HTML
<tr>
<td>Control 1 with onclick="javascript:Test(this);" </td>
<td>Control 2</td>
<td><span><div>Control 3</div></span></td>
</tr>
function Test(myThis)
{
//Here I would like to get references to the siblings of Control 1 (in this ex: Control 2, Control 3)
//and disable them. Any ideas?
}
I am using this approach of finding siblings as this is in a nested usercontrol with depth = 3 and ASP.NET refers to the controls with a prefix which is awfully hard especially if i have multiple instances of the control on the page.

if you're using a javascript library such as jQuery it becomes really easy:
$(this).siblings().disable();
http://docs.jquery.com/Traversing/siblings#expr
If you don't have jQuery or a similar library, then you'll have to do it manually:
function disableSiblingsOf(elem)
{
var nodes = elem.parent.childNodes;
for(var i=0; i<nodes.length; i++);
if(nodes[i] != elem)
nodes[i].disabled = true;
}
That should do the trick.

Add jQuery and use the following:
$(myThis).nextAll("td").each(function(){
// Code to "disable" them here, dunno what you mean by that though as they are tds.
});

I'll assume you don't have a Javascript library available, since I already see jQuery answers posted.
It depends a lot on the HTML rendered by your controls. However, you can probably just reference this.parent in a loop until this.tagName === 'TR' or this.parent becomes null. Then descend back down.

Related

using JavaScript, find the ClientID of .NET control nested deep within a master page

The short question:
*takes deep breath*
How I can ClientID of TableRow inside Table added to PlaceHolder, which is in a UserControl inside a Web Part added to a SharePoint page using a MasterPage?
The explanation:
I'm building a usercontrol that dynamically shows SPList items, one per Web.UI.Table(). The 2nd row of the Table() will be hidden at first, with an image used to initiate some JavaScript to hide/show the row at the clients browser (rather than use postback or ajax - I have reasons).
The Table() is then added to a PlaceHolder in a UserControl, which is then used by a WebPart, and that WebPart is added to a SharePoint Page, which of course uses a MasterPage. I'm having real trouble working out the JavaScript method to find the ClientID of the TableRow, given that it's nested so deeply.
My .ascx code looks something like this..
<script type="text/javascript">
function showHidden(itemId) {
var controlId = document.getElementById('<%= phDownloadTable.ClientID %>');
//alert(controlId);
document.getElementById(controlId).style.display = (document.getElementById(controlId).style.display == "table-row") ? "none" : "table-row";
}
</script>
<asp:PlaceHolder ID="phTable" runat="server"></asp:PlaceHolder>
and my .cs codebehind is something like this..
Table myTable = new Table();
TableRow hiddenRow = new TableRow();
hiddenRow.ID = "row" + itemId;
hiddenRow.Attributes.Add("style","display: none;");
... create TableCells and add to hiddenRow...
TableRow displayRow = new TableRow();
TableCell toggleCell = new TableCell();
Image toggleImage = new Image();
toggleImage.ImageUrl = "/images/myimage";
toggleImage.Attributes.Add("onclick","javascript:showHidden('" + hiddenRow.ClientID + "');
toggleCell.Controls.Add(toggleImage);
displayRow.Cells.Add(toggleCell);
... create more TableCells and add to displayRow
myTable.Rows.Add(displayRow);
myTable.Rows.Add(hiddenRow);
the result is that the toggleImage "onclick" attribute shows showHidden('row999');, which passes 'row999' to the JavaScript function, but I cannot figure out there how to get the full clientId of the TableRow it refers to.
The source of my page shows the clientId to be ctl00_SPWebPartManager1_g_eda9b9e9_4c7a_48e0_a2aa_fd8cdd65de6c_ctl00_row999, which is longer than I'm used to seeing, and seems to contain two 'ct100_' parts, suggesting multiple levels of controls.
Any ideas would be greatly appreciated. I've tried all the usual avenues (googleing for 'javascript .net control client id' and the like, but so far I've not found anything that helps. Most suggest document.getElementById('<%= myControl.ClientId %>')... which is fine, but I don't know 'myControl' - I need that send from the toggle image.
Fingers crossed!!
Kevin
If you cant set the client id, you should be able to set a class, and that should be respected by .nat.
Them you can select the element by class name.
JavaScript has no wildcard selection options. Try using jQuery, that makes things more flexible.
Then you can use something like:
$("tr[id*='<%= phDownloadTable.ClientID %>']").css("display", your value);
this way you will still find the right element, even when it's moved to another place on the page.
Here is a more detailed explanation on how to use these wildcard selectors:
http://api.jquery.com/attribute-contains-selector/
With plain JavaScript you can do a document.getElementsByTagName('tr') and then loop those to find the right object.
If you are using Framework 4.0 you can set the ClientIdMode of the page like this:
Page.ClientIDMode = System.Web.UI.ClientIDMode.Static;
That way you can have more predictable client ids. For example, you can have id's without all the ctl00_ prefixes.

How to get the radiobutton for corresponding datalisty item?

I want to convert this code to JavaScript code:
rdb1 = (RadioButton)DataList1.Items[i].FindControl("rdb1");
How can it be done?
Put a unique class on the radio button and then you can easily use jQuery to walk the DOM and find that control.
Here is an example of finding a control here on Stack Overflow.
Here is a tutorial of How to Get Anything You Want from a web page via jQuery.
Good luck, and hope this helps.
In JavaScript using the id attribute makes it easy to retreive a specific element since the id must be unique for all tags.
var radio1= document.getElementById("rdb1"); //this returns the element
Here is a simple tutorial on how to do other things after getting the element.
EDIT- I see you just want the selected value in javascript:
function radiochanged(){
var radio1= document.getElementById("rdb1");
var rdb1_value;
for (i=0;i<radio1.length;i++)
{
if (radio1[i].checked)
{
rdb1_value = radio1[i].value;
}
}
}
<input id="rdb1" type="radio" onClick="radiochanged()">

jQuery.click(): Can I get a reference to the synthetic event object passed to event handlers?

I have an <a> inside a <TD>, and I'm trying to have clicks on the <TD>, but outside the <A>, act like they were clicks on the <a>. I'm almost there:
HTML:
<TD class="somethingPretty">
Text
</td>
JS:
$('.anchor').click(function(ev){return confirm("go ahead?");});
$('somethingPretty').click(function(ev){
if($('.anchor').click()){
document.location = $('.anchor').attr('href');
}
}
The problem with this is that jQuery.click returns undefined, and I can't see how to get at the event object that's passed to the click handlers so I can interrogate it with isPropagationStopped and isDefaultPrevented. What's the right way to solve this problem?
Sometimes asking the question clearly is the best way to find an answer. Some strategic poking around the jQuery source led me to the following solution(using the markup above):
$('.somethingPretty').click(function(ev){
var syntheticClick = new $.Event("click");
syntheticClick.stopPropagation();
$('.anchor').trigger(syntheticClick);
if(syntheticClick.isDefaultPrevented()) return;
document.location = $('.anchor').attr('href');
}
This works for all event handlers except live-bound ones (those don't execute; my users will have to learn to click the anchor itself for them!). The tricky part here is that trigger takes a jQuery.Event in addition to the documented string.
How about this?
var a = $('.somethingPretty .anchor');
var td = $('.somethingPretty');
a.click( function(ev) { return confirm("go ahead?"); } );
td.click( function() { a.click(); } );
Did you try something like:
$("td.outer").add("td.outer a").click(function() {
// do stuff
});
You're going to want to find some way to ensure that whatever is in the function runs only once, since a click on the <a> will count both as a click on the <td> and the <a>.

Setting multiple literals that contain the same text in ASP.NET

I have instances where I need to dynamically load 5-10 literals with the same text value. It seems like there has to be a more elegant way of doing it than setting the TEXT property of all the controls to the same value. Any methods out there that I'm not aware of? I thought about setting a protected property on my webform, and then using inline code on my aspx page. Is that a good approach?
Edit: I should add that I also want to handle the situation where a designer could simply add another place to load dynamically to the aspx file on the web server without having to do another rollout.
Pseudo code:
var literals = new List<Literal>() { l1,l2,l3 ...} ;
literals.ForEach(x=>x.Text = "some value");
When faced with the same problem I often use:
litOne.Text = litTwo.Text = litThree.Text = "some value";
It's not perfect but at least it's on one line.
How about this?
foreach (ITextControl textControl in new[] { literal1, literal2, literal3 })
{
textControl.Text = "foo";
}
You could even be fancier and just loop through all controls and check only those that implement the ITextControl interface or so.

Forcing client ids in ASP.NET

I know that in the next version of ASP.NET we'll finally be able to set the clientids on System.Web controls without the framework doing it for us in a quasi-intelligent way e.g:
id="ctl00__loginStatus__profileButton"
Does anyone know a good method in the meantime to force the above id to something like
id="profileButton"
The main reason for this is manipulation of the clientids in jQuery when dynamically adding controls to a page. The problem I can see is changing the ids will break the Viewstate?
You have to use the ClientIDMode attribute:
<asp:xxxx ID="fileselect" runat="server" ClientIDMode="Static"/>
What I tend to do is dynamically generate javascript methods which handle this. You can do this in markup or code behind so for example:
<script language="javascript" type="text/javascript">
function doXYZ()
{
$("#" + getListBoxId()).css(...)
}
function getListBoxId()
{
return "<%=this.myListBox.ClientId>";
}
</script>
You can also build the functions in the code behind and register them.
EDIT
A couple months ago I needed to fix the id of some server controls, I managed to hack it in and I described my method here here.
Basically you need put the controls inside a naming container like a user control, and then override a couple of properties which prevents the child controls from getting their uniqueid.
The performance isn't great, but you can use this selector syntax to match messy ClientIDs:
$("[id$='_profileButton']")
That matches any element ending in _profileButton. Adding the leading underscore ensures that you're matching the desired element and not another element that ends in the substring "profileButton" (e.g. "myprofileButton").
Since it has to iterate over the entire DOM, the performance can be poor if you use it in a loop or several times at once. If you don't overuse it, the performance impact is not very significant.
Another way would be to wrap your control with a div or span with a static id, then access the control through that.
E.g.
<span id="mySpan">
<asp:TextBox id="txtTest" runat="server" />
</span>
You could then target input tags inside MySpan. (though I agree it would be nice to be able to specify a nice name, provided you could handle the naming conflicts...)
I have often run in to this "problem" while developing in asp.net webforms. In most cases I tend to use the css class of the element.
jQuery(".My .Container12")
Before starting to manipulate the id:s, perhaps that is a way you can handle it aswell? It's a simple solution.
There is another solution not mentioned which is to subclass the ASP.NET controls and force the IDs:
public class MyCheckBox : CheckBox
{
public string ForcedId { get;set; }
public override string ID
{
get
{
if (!string.IsNullOrEmpty(ForcedId))
return ForcedId;
else
return base.ID;
}
set
{
base.ID = value;
}
}
public override string ClientID
{
get
{
return ID;
}
}
}
Then use this where you know the IDs will never clash:
<mytag:MyCheckBox ForcedId="_myCheckbox" runat="server" />
If you are using lists you will need to write a ListControlAdapter, and also adapters for each type of list you're using (dropdown,checkbox,radiobutton,listbox). Alternatively cross your legs and wait for .NET 4.0.

Resources