views:

716

answers:

3

I include a JS file in a user control. The host page has multiple instances of the user control.

The JS file has a global variable that is used as a flag for a JS function. I need the scope of this variable be restricted to the user control. Unfortunately, when I have multiple instances of the control, the variable value is overwritten.

What's the recommended approach in a situation like this?

+3  A: 

Some options are to dynamically generate the javascript based on the ClientId of the User Control. You could dynamically generate the global variable for example.

Another option and one I would recommend is to encapsulate the global variable and function within an object, then your user control can emit the JS to create an instance of that object (Which can be dynamically named thus letting you scope the object as you see fit).

Edit

I don't have a working code sample that I can share but, I have done this in a couple different ways. the easiest method is to do this in the markup of your user control.

<script language='javascript'>
   var <%=this.ClientID%>myObject=new myObject();
</script>

Assuming your control has a clientId of myControl this will create a variable myControlmyObject.

Another way to do this would be to generate the script in the code behind you could register it using: Page.ClientScript.RegisterStartupScript().

JoshBerke
Josh - I like your recommended approach. Do you happen to have a code sample?
@Bob: See my response for a code sample showing how to encapsulate the variable within an object.
Ryan Shripat
Josh - Here's what I understand I should do:1. Create a class in JS with all the functions that are shared between UCs2. Create a instance of the class as shown in your code snippet3. If I call the JS function using myControlmyObject.FunctionA(), then the scope would be limited to the UC?
Should be that's what I do.
JoshBerke
Is this solution based on the concept of javascript polymorphism?
Nope its basically just an object you just have multiple instances in the global namespace uniquely named.
JoshBerke
This has helped me so much just this moment, many thanks!
Ian Devlin
+1  A: 

Well, if you have to keep with the current solution, you could rename your global variable to something like the following code, which should be in the .ascx file for your control:

<script type='text/javascript'>
var <%= this.ClientID %>_name_of_global_variable;
</script>

Where "this" is the asp.net control. That way, each control has a unique variable name, based off the client id. Make sure you update the rest of your javascript to use this new naming convention. The problem, it looks messy, and the variable names will become very long depending on where the control is embedded in the page.

Does that make sense? It should take minimal javascript modification to get it working.

Carl
The JS is in a separate file and I cannot use the <%= %> to inject the client id
The concept can be the same, if you register the javascript in your code-behind for that control.
Carl
(Register just the declaration of the global variable in the code-behind, that is)
Carl
+1  A: 

I would recommend refactoring your code such that all the common JS logic is stored in one place, not in every UserControl. This will reduce the size of your page by a good margin.

You can pass in the id of the UserControl to the common JS method(s) to differentiate between the UserControls.

For the issue of limiting the scope of your 'UserControl' variable, you could store some sort of a Key/Value structure to keep your UserControl-specific value - the Key would be the UserControl clientID, and the value would be the variable that you're interested in.

For example:

var UCFlags = new Object();
//set the flag for UserControl1:
UCFlags["UC1"] = true;
//set the flag for UserControl2:
UCFlags["UC2"] = false;

To access them, you simply pass the ClientID of the UserControl in to the UCFlags array:

myFlag = UCFlags["UC1"];

On the server-side, you can replace the constant strings "UC1" or "UC2" with

<%= this.ClientID %>

like this:

myFlag = UCFlags["<%= this.ClientID %>"];

You can still use the <%= this.ClientID %> syntax here even though the bulk of the JS is in a separate file; simply set

UCFlags["<%= this.ClientID %>"] = value;

before the call to embed the JS file.

Ryan Shripat
Ryan - I can have any number of user controls on the page. So, I cannot create the UCFlags array deterministically.UCFlags["UC1"] = true;UCFlags["UC2"] = false;......UCFlags["UCn"] = false;
@Bob: I understand, but with this method you don't need to know what and how many UCs there are - simply saying UCFlags["<%= this.ClientID %>"] = true will CREATE a property (dot ClientID) on the UCFlags object, and initialize the value to 'true'.
Ryan Shripat
Ah, I see that you are using hash tables in javascript. It looked like an array the first time I saw it :) Thanks
They call it 'associative arrays' in JS - check out this link: http://www.quirksmode.org/js/associative.html
Ryan Shripat