ASP.NET MVC3 Obtaining Auto-generated Form Element Id's - asp.net

Using #Html.TextBoxFor(m => m.MyField) will (normally?) result in <input id="MyField" name="MyField" type="text" value="" /> and if I want to access that element in jquery I do so as follows $("#MyField"). Is there a way to avoid manually typing the ID into the jquery selector? It seems clunky to me to do it this way as I'm coming from a classic asp.net background where you would pull the id of the element using the ClientID property. Therefore if the renderer changed how it generated the ID ones code automatically kept up-to-date. In the above example if I change MyField to MyNewField the compiler will remind me to change all the strongly typed references, but nothing will remind me to change my jquery selector.

Write a simple method that get a property and return it's name with reflection and use it like this:
static string GetVariableName<T>(Expression<Func<T>> expression)
{
var body = expression.Body as MemberExpression;
return body.Member.Name;
}
$('#' + #(GetVariableName(() => Model.MyField)))
Should work.

Related

asp.net 4.0: is there any equivalent of ClientIDMode for the names of INPUTs?

I have an asp:ListView whose ClientIDMode is set to Predictable. Its ItemTemplate contains an asp:textbox.
The ID of the textbox is acting as I expect it to, but its name is still using what looks like an AutoID-style algorithm:
<input name="lvFields$ctrl0$tbVal" id="lvFields_tbVal_somekey" type="text"/>
Is there a way for me to cause the name of the input to act like the ID does?
(Edit in response to questions below:)
The Name of the input element is what's in the POST data, so if a postback alters the list to which the ListView is bound (for example, exchanging two elements) the values from the textboxes end up associated with the wrong keys, because the framework is correlating them based on the Name and not the ID.
You can change the name of an Input by using the method from the following post but modifying it slightly:
how to remove 'name' attribute from server controls?
I over-rode the RenderChildren method on a Page control as I just wanted full control of the HTML for a few controls:
protected override void RenderChildren(HtmlTextWriter writer)
{
var unScrewNamesRender = new RenderBasicNameHtmlTextWriter(writer);
base.RenderChildren(unScrewNamesRender);
}
private class RenderBasicNameHtmlTextWriter : HtmlTextWriter
{
public RenderBasicNameHtmlTextWriter(TextWriter writer) : base(writer) { }
public override void AddAttribute(HtmlTextWriterAttribute key, string value)
{
if (key == HtmlTextWriterAttribute.Name && value.Contains("POLine"))
{
value = value.Substring(value.LastIndexOf("$") + 1);
}
base.AddAttribute(key, value);
}
}
You do need to know what you're doing if you attempt this, WebForms will think the control is missing so you can't use it in any postbacks. For my purposes, where I wanted to add an arbitrary number of multiple lines either server or client-side without having to deal with .Net Ajax controls, it works fine.
I'm pretty sure you can't change the name, especially when you modify the ClientIDMode. As an alternative, you can add a Title attribute. VS will flag this as unknown in the server side code, but it renders correctly in the HTML. If you're doing some client-side manipulation, you can address the input as such:
<script type="text/javascript">
$(document).ready(function () {
$('input:text[title="TextBoxName"]').datepicker();
});
</script>
As far as I know, there is no way to change the name of the input element. The name corresponds to the UniqueID property, which is generated by the system, and which you have no control over. Seems you have to find a way to achieve what yo want using only the control ID.
Both names are using the predictable pattern; originally, name also equaled ct100_ct100 etc. From what I see, that's a predictable name. Client ID value will always use _ between control prefixes and Unique ID (name attrib) will always use $. The two will always match, except for a few controls that leverage name for something (radiobuttonlist uses for grouping).
HTH.
I had the exact same problem once and had to use one of these properties exposed in "System.Web.UI.Control" to get clientside control name in server side.
Play around with these properties and construct the "Name" in server side yourself and use Request.Form("NameHere")
Me.ClientIDSeparator
Me.IdSeparator
Me.UniqueID
A jquery solution
function removeNameAttribute() {
$('input, select').each(function () {
$(this).removeAttr("name");
});
}
//Use a HtmlGenericControl
HtmlGenericControl input = new HtmlGenericControl("input");``
input.ID = "lvFields_tbVal_somekey";
input.Attributes.Add("name", "tbVal");
input.Attributes.Add("type", "text");
input.ClientIDMode = ClientIDMode.Static;

Way to update css properties on-the-fly based on form content?

I have a form on a website, in which one of the inputs is to be used to enter hexadecimal colour codes to be entered into a database.
Is there any way for the page to dynamically update itself so that if the user changes the value from "000000" to "ffffff", the "colour" CSS property of the input box will change immediately, without a page reload?
Not without Javascript.
With Javascript, however...
<input type='text' name='color' id='color'>
And then:
var color = document.getElementById('color');
color.onchange = function() {
color.style.color = '#' + this.value;
}
If you are going to go the Javascript route, though, you might as well go all out and give them a color picker. There are plenty of good ones.
CSS properties have corresponding entries in the HTML DOM, which can be modified through Javascript.
This list is somewhat out of date, but it gives you some common CSS pieces and their corresponding DOM property names.
Granted, a JS lib like like jQuery makes this easier...
You can use Javascript to achieve that.
As an example:
Your HTML:
<input type="text" id="test" />
Your JS:
var test = document.getElementById('test');
test.onchange = function(){
test.style.color = this.value;
};
But this doesn't check the user's input (So you would have to extend it).

$('#<%= txtFirstName.ClientID%>'). What do $ and # do in this code?

$('#<%= txtFirstName.ClientID%>').show();
Trying to send ClientId to external Javascript file using server tags
as a parameter
<input type="text" ID="txtFirstName" runat="server" maxlength="50"
class="DefaultTextbox" style="width:180px;"
value="First Name"
onfocus="ControlOnFocus('First Name',$('#<%= txtFirstName.ClientID%>').show())"
onblur="ControlOnBlur('First Name')"/>
function ControlOnFocus(CompareString,ControlId)
{
alert(ControlId);
}
$() is a short alias for the main jQuery function, also called jQuery(). You pass it a CSS selector, and in CSS, # means "the HTML element with ID...". That ID is in the ClientID variable in this program, apparently. The show() call then makes the named HTML element appear.
It seems your script uses jQuery.
$('#<%= txtFirstName.ClientID%>').show() will return the jQuery object containing the element with attribute id=<%=txtFirstName.ClientID%>, and not the ClientID value.
I guess what you really mean is this :
<input type="text" ID="txtFirstName" runat="server" maxlength="50"
class="DefaultTextbox" style="width:180px;"
value="First Name"
onfocus="ControlOnFocus('First Name','<%= txtFirstName.ClientID%>')" // <= pass only the ClientID to your function
onblur="ControlOnBlur('First Name')"/>
function ControlOnFocus(CompareString,ControlId)
{
$('#'+ControlId).show(); // <= do the show action here, in your function
alert(ControlId);
}
Bud, $ is an alias for some javascript framework like jquery or prototype, the # represents an ID at the DOM. Just like CSS, those frameworks allow you to select elements using CSS syntax (. for classes, # for ids, etc).
So $("#test") works almost like getElementById('test')
The jQuery syntax always begins with $, the # indicates that function show() is to be applied on the element whose Id is provided. Lets say the id is txtFirstName, then writing $('#txtFirstName') is equivalent to document.getElementById('txtDirstName') in classic Javascript. This will select the element from the Document Object Model(DOM) by the id provided. Once the element is selected, different jQuery functions can be executed on that reference.
The show function makes the control/element visible. Similarly you can use .hide() to hide the element.

Passing hidden field from one page to another in querystring

I want to pass a query in a hidden filed from 1 page to another by querystring.
Can anyone help me out with the logic?
It's worth taking the time to learn jQuery. It's not very complicated, and it makes writing javascript much easier. There are also many jQuery plugins, such as jquery.url.
Also, as other posters have suggested, you may not wish to put the hidden field's value in the query string if you care about it being displayed to the user. However, if the data is present in a hidden field it will always be possible for a user to find it if they care to look.
If you really do want to put the hidden field in the query string and then extract it via non-jQuery javascript:
hiddenFieldPage.aspx
This form will take the user to processingPage.aspx?datum=someValue when it is submitted. You could probably also just use an ordinary link if nothing else needs to be submitted at the same time.
<form method="GET" action="processingPage.aspx">
<input type="hidden" name="datum" value="someValue">
<input type="submit">
</form>
or, inserting the value from code-behind:
RegisterHiddenField("datum", "someValue");
processingPage.aspx
This script will pop-up an alert box with the value of "datum" from the URL - assuming the form's method is set to "GET":
<script type="text/javascript">
function getUrlParam( key ) {
// Get the query and split it into its constituent params
var query = window.location.search.substring(1);
var params = query.split('&');
// Loop through the params till we find the one we want
for( var i in params ) {
var keyValue = params[i].split('=');
if( key == keyValue[0] ) {
return keyValue[1];
}
}
// Didn't find it, so return null
return null;
}
alert( getUrlParam("datum") );
</script>
If the form's method was set to "POST" (as it usually would be in ASP.NET), then "datum" won't be in the query string and you'll have to place it on the page again:
RegisterHiddenField( "datum", Request.Form["datum"] );
To retrieve the hidden value on the second page:
var datum = document.Form1.item("datum").value;
alert( datum );
You can easily submit a form on one page that points to another page using the action parameter. For instance, inside of page1.aspx put the following:
<form action="page2.aspx" method="GET">
<input type="hidden" name="username" value="joenobody" />
<input type="submit" />
</form>
Since you're using "GET" as the method instead of "POST", you could potentially use Javascript to parse the URL and get the value that was passed. Alternatively, you could use ASPX to store the value of the "username" field somewhere else on the page. I don't know ASPX (or ASP, or anything Microsoft really), but if you can find a way to output something like the following (and are using jQuery), it may do what you require. Honestly though, it sounds like you are going about something all wrong. Can you modify your question to be a bit more specific about what the general object is that you are attempting to accomplish?
<div id="some_div"><%= Request.form("username") %></div>
<script type='text/javascript'>
var value_needed = $('#some_div').html();
</script>
<form method="get">
Assuming you mean hidden in the HTML form sense, your field will be submitted along with all the other fields when the form is submitted. If you are submitting via GET, then your "hidden" field will show up in plain text in the URL. If you don't want the data in the hidden field to be accessible to users, don't put an understandable value in that field.
If you are using aspx, you do not need to parse the query string using JavaScript, or even use <form method="GET" ...>. You can POST the form to the second aspx page, extract the value in C# or VB then write it to a client-side JavaScript variable. Something like this:
page1.aspx:
<form method="POST" action="page2.aspx">
<input type="hidden" name="myHiddenServerField" value="myHiddenServerValue">
<input type="submit">
</form>
page2.aspx:
<script type="text/javascript">
var myHiddenClientValue = '<%= Request.Form['myHiddenServerField']; %>';
</script>
The above would set the client-side JavaScript variable called myHiddenClientValue to a value of 'myHiddenServerValue' after the POST.
This can be a bad idea because if myHiddenServerField contains single quotes or a newline character, then setting it on the client in page2.aspx can fail. Embedding ASP.NET Server Variables in Client JavaScript and Embedding ASP.NET Server Variables in Client JavaScript, Part 2 deals with specifically these issues, and solves them with a server-side class that ensures values being written to the client are escaped correctly.
If you use method="get" on an HTML form then any hidden inputs in that form will be converted to query parameters.
See also Jeremy Stein's answer.

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