33

Is there a way to use "<%= someObject.ClientID %>" in an external javascript file?

If I use the code

<%= someObject.ClientID %>

in a script tag inside my as(c/p)x page, it works fine. On the rendered page, the ClientID is resolved. Howvever, if I put in an external JS file and just add:

It doesn't. Is there a way to do this or am I stuck with leaving that code in the as(c/p)x file?

Side question -- what is the act of doing <%=... %> in your markup file called?

Beygi
  • 1,918
  • 1
  • 16
  • 22
Matt
  • 25,943
  • 66
  • 198
  • 303
  • JS files are not processed by the ASP.NET runtime, so it won't work. I too hate the massive amount of code that ends up inline because of this... You can make functions and pass parameters, but the server side blocks can't go into the JS files. – Zachary Jun 30 '11 at 23:16
  • Certainly there is a way to configure IIS so that JS files also go through the same pipeline as aspx/ashx files? – Xavier Poinas Jun 30 '11 at 23:26

8 Answers8

33

If you really want to do this you can do following

<%@ Page ContentType="text/javascript" Language="C#" AutoEventWireup="false" %>
<%@ OutputCache Duration="86400" Location="Any" VaryByParam="None" %>

var time = "<%= DateTime.Now.ToString() %>";
alert(time);

And then reference it in your page

<script src="Scripts/file.aspx" type="text/javascript"></script>

Note When using mentioned method, the only way to pass target page controls client-ids, is to store client id as string in a public property, and then reference it using new instance of that page

If the only thing that made you to do this is client-id then you can use following ASP.NET 4 feature

<any-tag ID="myCustomId" runat="server" ClientIDMode="Static" />

You can also put all your client-ids in C# class then serialize it using JSON and render it in script tag, could be smart way for ASP.NET prior to version 4.

Note using serialization method you have possibility to change any tag ids without worrying about javascript element usages, remember that this is not even possible with ASP.NET 4 ClientIDMode

See

Page-Code-File

public partial class About : System.Web.UI.Page
{
    ...

    protected string GetTagIds()
    {
        return new JavaScriptSerializer()
                    .Serialize(new
                     {
                            myButton = Button1.ClientID,
                            myCalendar = Calendar1.ClientID
                     });
    } 

    ...
}

Page-ASPX

<script type="text/javascript">
    var IDs = <%= GetTagIds() %>;
</script>

Anywhere

<script type="text/javascript">
    IDs.myCalendar.doSomthing...
</script>

There is another option that you can pass all javascript files to ASP.NET handler but i don't recommend it, because of just a single javascript file you make asp.net handler busy.

Code Blocks

<% inline code %>

This is an inline code definition which you can execute codes in it :

<% Response.Write("Hi"); %>

<% while(i < 0) { %>
      <% 
         Response.Write(i.ToString()); 
         i++;
      %>
<%}%>

Note You have to include ';' on end of each statement when using inline code with C# language, you can change inline language using page directive language attribute

<%= inline expression %>

This one equals to calling Response.Write your self, see:

<%= "Hi" %> equals to <% Response.Write("Hi"); %>

Note You shouldn't include ';' when using inline expression

<%: encoded inline expression %>

This one equals to :

Response.Write(HttpUtility.HtmlEncode("<script type="text/javascript">alert('XSS');</script>"))

And is used for security reasons --XSS, any input HTML to this one outputs HTML encoded text which is safe to display user entered contents in page.

Note You shouldn't include ';' when using encoded inline expression

<%$ expressionPrefix: expressionField %>

This one is expression that you can use to bind values from ConnectionStrings, Resources and AppSettings

expressionPrefix possibilities is

  • AppSettings
  • ConnectionStrings
  • Resources

expressionField is the property of specified expressionPrefix that you need, see:

// AppSettings
<asp:Label ... Text="<%$ AppSettings: version %>" />

// ConnectionStrings
<asp:SqlDataSource ... ConnectionString="<%$ ConnectionStrings:dbConnectionString %>" />

// Resources
<asp:Label ... Text="<%$ Resources: Messages, Welcome %>" />

Note You shouldn't include ';' and you can use expressions only on ASP.Net controls attributes

<%# data-binding expression %>

You can use this anywhere inside controls with data-binding support, and usually is used by Eval and Bind methods.

<asp:DropDownList SelectedValue='<%# Bind("CategoryID") %>' 
                  DataSourceID="CategoriesDataSource"
                  DataTextField="CategoryName"
                  DataValueField="CategoryID"
                  runat="Server" />

Which one Eval or Bind?

Using Bind you have two-way binding set over specified attribute of ASP.NET control see the mentioned drop-down, it is using Bind that means if end-user selects a value and then submit the page, drop-down will not loose its selected value.

Use Eval just for displaying data.

<asp:FormView ...>
     <ItemTemplate>
          <a href='Eval("Link")'>Eval("LinkText")</a>
     </ItemTemplate>
</asp:FormView>

<%@ text template directive %>

<%@ Page ...%>
This one is Page Directive

<%@ OutputCache...%>
This one is OutputCache Directive and so on...
Beygi
  • 1,918
  • 1
  • 16
  • 22
20

This is totally possible.

In your .aspx page, create a script reference to an aspx page that contains your javascript code:

<script src="../MyJavaScriptFile.js.aspx" type='text/javascript'></script>

Then, in MyJavaScriptFile.js.aspx you can write the following:

<%@ Page Language="C#" AutoEventWireup="false"  ContentType="text/javascript" %>

<% 
    var foo = new Whatever();
    foo.ClientId = 123;
%>

// Start Javascript
var clientId = <% HttpContext.Current.Response.Write(foo.ClientId); %>;

.

Also helpful - this technique supports querystring parameters:

 <script src="../MyJavaScriptFile.js.aspx?username=<% somevalue %>" 
       type='text/javascript'></script>

Then, in MyJavaScriptFile.js.aspx, I can reference the value with

var username = '<% Request.QueryString["username"] %>';

It's not the "best practice" way to do things, but it gets the job done in a way that my caveman brain can understand without resorting to fancy workarounds.

Daniel Szabo
  • 7,181
  • 6
  • 48
  • 65
  • 1
    How do you reference for example a button client id in this way?!...you will use just a string, OK so why don't we do that in javascript file itself?!.... – Beygi Jul 02 '11 at 22:24
  • 1
    @Beygi - There are a couple ways. You can pass it as a url parameter in the reference to the file or you can save the button's client id to a session variable and reference it in your .js.aspx file with <% Request.QueryString["SessionVariableName"] %> – Daniel Szabo Jul 02 '11 at 22:31
  • 2
    Don't use `<% Request.QueryString[...] %>` in javascript files, it is vulnerable to XSS, and that means if the value somehow shared between all users then malicious user can even hijack all users sessions... – Beygi Jul 02 '11 at 22:31
  • If you're not comfortable using Request.Querystring, store it as a session variable then and reference it that way in your file. – Daniel Szabo Jul 02 '11 at 22:33
  • 1
    @Beygi - How would it not work? The clientID gets generated, saved to session, and then the Javascript file uses that ID to reference its target. The only way they change is if you manually change them in the pres layer. Either way, the javascript file is using the correct ID. – Daniel Szabo Jul 02 '11 at 22:41
  • Storing client ids in session because we are not comfortable with dynamic script tag in page!... – Beygi Jul 02 '11 at 22:41
  • You're right about session, but we have to check if it's null and storing client ids in it again yes yes, you're right,But what if i have a save button in a page an another one in another page with the same name but not same control hierarchy!??? – Beygi Jul 02 '11 at 22:50
  • What if we're using other session modes than inprocess, making network busy for saving each client id!...each page with 10 control and each user 10 request means 100 request for each user just for storing client ids in, SqlServer or StateServer. what i'm saying is session is not right place for client id neither QueryString...imagine if google or yahoo do things like this – Beygi Jul 02 '11 at 22:59
  • 1
    Your assuming that he's going to store every single client ID in his page in session state. If he's only going to store a single client ID, it's not a big deal at all. – Daniel Szabo Jul 02 '11 at 23:30
  • no, storing client-id in javascript using querystring is not a problem neither security risk, like just i said session-state is not right place for client id not even QueryString... – Beygi Jul 03 '11 at 07:55
  • I get an HTTP 500 on MyJavaScriptFile.js.aspx... any ideas why? – dlchambers Jul 23 '15 at 18:17
3

This adds a bit more HTML but it works; wrap each server control in a div...

<div id="myContainer">
    <asp:HiddenField ID="hdMyControl" runat="server" /></div>

Set the HiddenField's value in the code behind

hdMyControl.Value = "something";

Then in your external JS file you can get the server control's value

$(document).ready(function () {
    var myValue= $('#myContainer input[type=hidden]').val();

I'm not sure that it matters, but I'm adding the script reference to the page via the codebehind using RegisterClientScriptBlock

Mark B
  • 1,166
  • 1
  • 19
  • 31
3

I like to embed a single line of javascript on my page.

<script type="text/javascript">
   Application.init({variable1: "value1", variable2: "value2"...});
</script>

It's poor practice to have a ton of javascript rendered on your page, but it is common to need to pass initialization values to your javascript from the server. This allows you to do it without a whole bunch of unnecessary code and without polluting the global namespace with callback functions. I usually replace Application with some project specific global wrapper.

jesse reiss
  • 4,509
  • 1
  • 20
  • 19
2

You could create an empty callback function in the external file:

var MyCallback = function () { };

And then in the asp/cx do something like:

MyCallback = function () {return "<%= someObject.ClientID %>";}

And then, back in your external file:

var myClientID = MyCallback();
Xavier Poinas
  • 19,377
  • 14
  • 63
  • 95
Michael
  • 4,010
  • 4
  • 28
  • 49
  • 1
    @myself, I guess it's not really a callback but more a function variable? hook? delegate? – Michael Jun 30 '11 at 23:23
  • If you're just trying to deal with the way ASP.NET builds-up server control id's, and don't want to deal with finding them all everytime it changes, use ClientIDMode="Static", and it won't change. Be careful not to do this on two controls with the same id, of course. – Michael Jun 30 '11 at 23:28
1

No, it won't work like that because the javascript file is being transmitted independently as a separate file and it isn't parsed by ASP.NET on the way out, while your aspx file IS being parsed and the .NET engine is replacing the tag w/ the actual value.

Now when your objects call those JS functions, what they could do is pass references to themselves into the function, or even pass in a dictionary list of some sort with your own key for what the control is and the assigned name.

One thing to think about as well - IF you are going to make a JS file independent of an ASPX page, then that JS file absolutely should not presume to know anything about the specific controls of the aspx file that calls it - because later on someone else might decide, "Oh that's a good JS file, I'll incorporate it too" and it won't work for them cause their objects wont match yours. Thus the pattern you should follow would have to be more generic - thus why you'd want to pass in references or lists of identifiers.

The Evil Greebo
  • 7,013
  • 3
  • 28
  • 55
1

The server tag <%= %> is used to enter code that is processed on the server.

You cannot use <%= someObject.ClientID %> in an external js file because the server tag is an asp.net thing and js doesn't know what this is.

If you use ASP.NET 4 you can set the client id in the properties of the control making it predictable.

If you don't use ASP.NET 4 you could put this client id in a hidden field or an inline js variable.

dexter
  • 1,217
  • 9
  • 12
-5

Use the standard prefix identifier in script source files:

document.getElementById("ctl00_ContentDetail_textboxelename").value = "";
document.getElementById("ctl00_ContentDetail_radioORcheckboxelename").checked = false;
document.getElementById("ctl00_ContentDetail_elename").style.visibility = "hidden";
var javaele = document.getElementById("ctl00_ContentDetail_elename");
var boolIsChecked = document.getElementById("ctl00_ContentDetail_radioORcheckboxelename").checked;
  • 4
    No, no, NO. Don't *EVER* do this. As soon as you add another container control to your page the IDs will all change and your JS will break. Just no. – Ian Kemp Aug 13 '13 at 11:45