I am developing a user control (ascx) in ASP.NET which uses javascript for manipulating controls. Currently the javascript code is inlined and uses <%= somecontrol.ClientID %> to get the control it needs.
I want to put the javascript file in external file but from external file I cannot use the above syntax for retrieving controls. I have read about possible solutions in this and this answers but the problem is that the user control can be placed multiple times on page. This means that the Controls array (mentioned in the answers) will be rendered several times with different items. As a result the script will not be able to retrieve the id it needs. If I put <%= ClientId %> in the name of array that holds items then I will have the same problem as I am trying to solve.
Any ideas?
Ok, a different approach, that I try to use a JavaScript-class style, and then initialize it for each control.
In the external javascript file, write your code as:
function oNameCls(ControlId1) {
this.ControlId1 = ControlId1;
this.DoYourWork1 = function() {
// use the control id.
// this.ControlId1
}
this.DoYourWork2 = function() {
// use the control id.
// this.ControlId1
}
}
And on the control do the call like that.
<script language="Javascript" type="text/javascript">
// init - create
var <%=this.ClientID%>MyCls = new oNameCls(<%=Control1.ClientID%>);
// do your work
<%=this.ClientID%>MyCls.DoYourWork1();
</script>
Hope now help better.
The way I solve this problem is to use CSS classes or place the controls within containers with known IDs and then traverse into the container's children to get the actual controls. For example:
<asp:TextBox ID="Something" runat="server" CssClass="mycontrol" ... />
Could be accessed via:
jQuery('.mycontrol');
Or:
<div id="ControlContainer">
<asp:TextBox ID="Something" runat="server" ... />
</div>
Could be accessed via:
jQuery("#ControlContainer input[type='text']");
The only real problem with this approach is you're tying your code to specific markup on the page, which can be a hassle if the markup changes a lot.
What about a hidden variable:
<input type="hidden" id="ClientId" value="<%=ClientId %>">
Then from your js:
$("#" + $("#ClientID").val())
Or, put the hash in:
<input type="hidden" id="ClientId" value="#<%=ClientId %>">
...
$($("#ClientID").val())
If you want to find a specific control when there could be multiple copies, this can't be done. How would the external javascript know which of the n controls you wanted?
How can rig the behavior up to a class and find the elements relative to the position of the action control, like this:
UserControl:
<div class="myControl">
<asp:Button id="MyButton" runat="server" Text="Click Me" />
<div style="display:none;">Show me!</div>
</div>
If you jQuery was written to be relative like this:
$(".myControl input").click(function() {
$(this).next().slideDown();
});
In this case, it doesn't matter what the specific IDs are, as long as you can navigate the DOM relatively to the controls you need. Even if it's more complex like .closest("div").next().find(".bob").prev()...whatever you need to get there works.
Related
I know I can place any value from my code behind virtually anywhere on my aspx by using:
<%=myString%>
I also know that in order for me to make a field required using twitter bootstrap I need to use required before my tag closes as in:
<asp:TextBox ID="txtFName" runat="server" CssClass="standard_tb" required/>
In my project I want to be able to set that variable to required or null.
When I try using the method above I get the The server tag is not well formed if i use <%#myString%> within my label or I get the error Server tags cannot contain <% ... %> constructs if I use <%=myString%>
How do I get around this?
As you've seen you cannot add <% %> tags to a .NET server control.
What you need to do is in the code behind set:
if (someCondition)
txtFName.Attributes.Add("required", null);
else
txtFName.Attributes.Remove("required");
If you need XHTML compliance then instead you'd use the line:
txtFName.Attributes.Add("required", "required");
Which would render as:
<input id="txtFName" class="standard_tb" required="required" />
I have a that would result in some uncompilable code in the designer.cs file:
<div id="tabs-1-2-3"></div>
If I add a runat="server" property, my designer file won't compile for obvious reasons.
Is there any way to add an extra property that wil be used internally as the id?
If you don't have runat="server" then you can access it through the old school way.
<input type="text" id="text1" name="text1" />
then from server side use
Request["text1"]
for div:
The best way to do this would be some form of ajax, since your client side script would be able to read that contents and pass it to a server side method
Access in code behind isn't possiable without runat="server" attributes
Use an <asp:Panel /> which will turn into a <div> in the HTML page.
This is a two-fer, and I've looked in a lot of places and could not put together a solution for this particular scenario.
I will have the user enter multiple values using a single text field, such as:
<div style="margin-left: 5px; display: block;">
<div id="divTemplateLine" style="display: none;">
x
</div>
</div>
Using Javascript, the Add button will keep cloning divTemplateLine and include the text within the parent node.
I got all that working fine.
Now, I'd like to read all these lines (salmon, soup, miso, japanese) on the postback.
I'm assuming at this point I'm in the realm of parsing HTML, since these div's I added are not "runat" server.
One answer could be using a server-run hidden value, where the Javascript will keep appending to it.. yes that's a good solution, but I'd like to see how I can parse out the HTML elements and nodes just as I did in Javascript, because my real scenario is more complicated than a single value, so a hidden value will not quite do.
Any input and/or judgment is welcome.
The solution is to keep two versions of your data, one that you show on the user, and one on a hidden input that you post back and get the data that user select and keep.
For example, when your user enter the 'salmon', you place it both on html render, and on an input hidden control with your way of serialize. When your user remove it, you remove it from your hidden control also.
At the end you going to have something like that, and you post it back and analyse it and save it on your database.
<input name="final_select" type="hidden" value="salmon;soup;miso;japanese" />
#BeemerGuy: take one text box and auto complete extender as follows:
<asp:TextBox ID="txtCustName" AutoPostBack="true" AutoComplete="off" runat="server"
OnTextChanged="txtCustName_TextChanged" />
<cc1:AutoCompleteExtender ID="ace1" TargetControlID="txtCustName" ServiceMethod="GetCustomers"
MinimumPrefixLength="1" OnClientItemSelected="ace1_itemSelected" FirstRowSelected="true"
runat="server" />
Auto Complete Extender has service method property which will be called when you enter text on text box and will add text box value in list view
<<****** Webmethod code is here ******>>
ListBox list = new ListBox();
[WebMethod]
public static DataSet GetCustomers(string prefixText)
{
list .Items.Add(New ListItem(prefixText, 0));
}
I have a asp file upload for pictures and what I want to do is, when the file chosen has the same name as the previous file it should pop something up that says "This image name already exists, do you want to replace it? if yes then it would just override the current picture with the new one but if not then just leave it alone. How can I do this?. Right now I have this. Also if the solution is in javascript I could also use that (but i am not too good with javascript :) ) Thank you
<div class="style">
Choose an Image: <asp:FileUpload ID="getImage" runat="server" Width="150px" BorderStyle="Inset" EnableViewState="true" />
<asp:RegularExpressionValidator ID="RegularExpressionValidator"
runat="server" ControlToValidate="getImage" CssClass="Error" Display="dynamic" ValidationExpression=".*(\.[Jj][Pp][Gg]|\.[Gg][Ii][Ff]|\.[Jj][Pp][Ee][Gg]|\.[Pp][Nn][Gg])" ErrorMessage="Select a correct file format"></asp:RegularExpressionValidator>
</div>
Please be aware I am a total newbie with Javascript so if that is what's going to work please explain as if I was a 5 year old.
I really appreciate the help.
My solution will perform the check just before postback. I also use jquery a little bit.
The important piece of the puzzle here is retrieving the previous file name. I created a PageMethod to do this part. So in my aspx.cs file I have a function that looks like this:
using System.Web.Services;
.......
[WebMethod()]
public static string GetPreviousFileName()
{
//put logic here to get the filename to compare against.
return "somefilename.ext";
}
You'll need to implement your own logic for how to retrieve the file name. Another, simpler but less flexible, approach for handling the previous file name would be to add an asp:hiddenfield to your page and populate it with the name of the previous file on page load. Then you could compare by reading $('#<%= hiddenField.ClientID %>').val().
Next I used the following code for my file upload control and a submit buton:
<asp:ScriptManager ID="sm" runat="server" EnablePageMethods="true" />
<div>
<asp:FileUpload ID="fu" runat="server" />
<asp:Button ID="btnUpload" runat="server" OnClientClick="return checkDuplicateFile();" Text="Upload File" />
</div>
Two important things to note here: The ScriptManager has EnablePageMethods="true" and the asp:button has an OnClientClick attribute specified. Lastly, the javascript part of the solution which retrieves the value from the page method and and compares the file names:
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
var oFilename = "";
$(function () {
//get original file name on page load
PageMethods.GetPreviousFileName(function (result) {
oFilename = result;
});
});
function checkDuplicateFile() {
var newVal = $('#<%=fu.ClientID %>').val();
var newValFile = newVal.substr(newVal.lastIndexOf("\\") + 1);
//returning true causes postback, returning false stops postback.
if (newValFile == oFilename) { return confirm("This image name already exists, do you want to replace it?"); }
else return true;
}
</script>
Couple of things going on here. We use our pagemethod to pull in our old filename from the page method on page load (PageMethods.GetPreviousFileName). Next we setup the function which will be called by our buttons onClick event (client side). The <%=fu.ClientID %> snippet of code will output the client side id of the file upload control for use in our javascript. I do a substring on the file path and extract the file name by pulling back only the text after the last '\' and do the compare.
As my comment in the function says, returning true/false from a function called in the OnClientclick event determines whether a post back occurs. So if the user clicks yes in the confirmation box then a postback occurs, else if they click no then none occurs.
Hope that at least gets you going in the right direction.
Add the code below to your submit button
OnClientClick="return confirm('Are you sure you want to delete this file?')"
Edit as someone pointed out this will ask this question without taking in concern previous file and new one. It will do basic job.
My question is whether you doing this for edit mode or in new item mode. I mean are you editing item or adding new one on page you are interested to check?
I'm trying to grab a div's ID in the code behind (C#) and set some css on it. Can I grab it from the DOM or do I have to use some kind of control?
<div id="formSpinner">
<img src="images/spinner.gif" />
<p>Saving...</p>
</div>
Add the runat="server" attribute to it so you have:
<div id="formSpinner" runat="server">
<img src="images/spinner.gif">
<p>Saving...</p>
</div>
That way you can access the class attribute by using:
formSpinner.Attributes["class"] = "classOfYourChoice";
It's also worth mentioning that the asp:Panel control is virtually synonymous (at least as far as rendered markup is concerned) with div, so you could also do:
<asp:Panel id="formSpinner" runat="server">
<img src="images/spinner.gif">
<p>Saving...</p>
</asp:Panel>
Which then enables you to write:
formSpinner.CssClass = "classOfYourChoice";
This gives you more defined access to the property and there are others that may, or may not, be of use to you.
Make sure that your div is set to runat="server", then simply reference it in the code-behind and set the "class" attribute.
<div runat="server" id="formSpinner">
...content...
</div>
Code-behind
formSpinner.Attributes["class"] = "class-name";
This question makes me nervous. It indicates that maybe you don't understand how using server-side code will impact you're page's DOM state.
Whenever you run server-side code the entire page is rebuilt from scratch. This has several implications:
A form is submitted from the client to the web server. This is about the slowest action that a web browser can take, especially in ASP.Net where the form might be padded with extra fields (ie: ViewState). Doing it too often for trivial activities will make your app appear to be sluggish, even if everything else is nice and snappy.
It adds load to your server, in terms of bandwidth (up and down stream) and CPU/memory. Everything involved in rebuilding your page will have to happen again. If there are dynamic controls on the page, don't forget to create them.
Anything you've done to the DOM since the last request is lost, unless you remember to do it again for this request. Your page's DOM is reset.
If you can get away with it, you might want to push this down to javascript and avoid the postback. Perhaps use an XmlHttpRequest() call to trigger any server-side action you need.
Add the runat="server" attribute to the tag, then you can reference it from the codebehind.
Add runat to the element in the markup
<div id="formSpinner" runat="server">
<img src="images/spinner.gif">
<p>Saving...</p>
</div
Then you can get to the control's class attributes by using
formSpinner.Attributes("class")
It will only be a string, but you should be able to edit it.
How do you do this without runat="server"? For example, if you have a
<body runat="server" id="body1">
...and try to update it from within an Updatepanel it will never get updated.
However, if you keep it as an ordinary non-server HTML control you can. Here's the Jquery to update it:
$("#body1").addClass('modalBackground');
How do you do this in codebehind though?
If you do not want to make your control runat server in case you need the ID or simply don't want to add it to the viewstate,
<div id="formSpinner" class="<%= _css %>">
</div>
in the back-end:
protected string _css = "modalBackground";
If all you want to do is conditionally show or hide a <div>, then you could declare it as an <asp:panel > (renders to html as a div tag) and set it's .Visible property.
To expand on Peri's post & why we may not want to use viewstate the following code:
style="<%= _myCSS %>"
Protected _myCSS As String = "display: none"
Is the approach to look at if you're using AJAX, it allows for manipulating the display via asp.net back end code rather than jquery/jscript.