Get child controls on server control using javascript ASP.NET - c#

I've create a basic composite server control that contains a button.
<Custom:Class1 ID="testClass" ClientInstanceName="test1" runat="server"></Custom:Class1>
I would like to be able to get to the child controls using javascript for example:
var myButton = testClass.FindControl('btnTest');
Is there anyway to do this?

Create a client side object to represent your server side control (javascript class). Put a collection of references to the child controls on the client side object. Then on the server side OnPreRender event create or load a script to define your client side object and at the same time pass the collection of references to its constructor.
Example of how to embed a javascript file containing the clientside object definition (put this somwhere above the namespace declaration:
[assembly: WebResource("myNS.stuff.clientSideObj.js", "application/x-javascript")]
namespace myNS.stuff
{
Example of how to register the WebResouce (OnPreRender):
ClientScriptManager cs = this.Page.ClientScript;// Get a ClientScriptManager reference from the Page class.
Type csType = this.GetType();// Get the type from this class.
//Register an embedded JavaScript file. The JavaScript file needs to have a build action of "Embedded Resource".
String resourceName1 = "myNS.stuff.clientSideObj.js";
cs.RegisterClientScriptResource(csType, resourceName1);
Example of creating a script to declare an instance of your client side object (OnPreRender):
String childControlIDsList= getChildControlList();//I am not writing this one.. just look up javascript arrays.
String uniqueScriptKey = "myKey";
StringBuilder theScript = new StringBuilder();
theScript.AppendLine("var myObj = new clientSideObj(" + childControlIDsList + ");");
theScript.AppendLine("window['myClientControl'] = myObj;") //create a client side reference to your control.
cs.RegisterStartupScript(csType, uniqueScriptKey, theScript.ToString(), true);
I will leave the client side object definition up to you... Hope that helps!

This is for Sharepoint visual web controls, but the same general process applies:
http://lemonharpy.wordpress.com/2011/07/20/expose-clientid-to-javascript-in-sharepoint-2010-visual-web-control/
Essentially, in the code behind on the page you get a reference to the ClientId on the page, and then expose that up as a javascript variable that you can prepend onto your jQuery selectors.
I feel this is a little hacky - but I think it gets the job done...

If you're using .net 4.0 you can set the the 'ClientIDMode' property on the button to Static then set the ID property to something like ID="myButton" and access it with with jquery like so
$("#myButton")
If you dont use jquery you can use
document.getElementById("myButton")
If you are using the control multiple times in the form you could prefix the button id with your custom controls id. Remember to set your custom controls ClientIDMode property to static as well.
<asp:Button ID="<%=Me.Id%>_myButton " ClientIDMode="Static" runat="server"/>
Not entirely sure this is even good practice or if it will work but you can try it.( remember to set your custom controls id

Related

C# Get id of dynamically created labels

I need to be able to set the IDs of dynamically generated labels instead of letting SharePoint prefix my labels with a long cryptic id of its own. Is this possible or is there another property of label that I can use as a unique identifier in a separate method?
Label animal = new Label();
animal.ID = cat;
The id for this label will be something like:
ctl00_m_g_e0c173c0_edf3_4a99_a1dd_7bef33144c0b_ctl00_cat
I need it to be cat.
To force the client-side id to be the same as the server-side id, use:
animal.ClientIDMode = ClientIDMode.Static;
You cannot set the ClientId of a server control. It is a read only property.
The cryptic id you see is actually your control heirarchy.
If you're attempting to access the control with javascript and are using jQuery, you can just the various regex selectors:
$("label[id$='cat']")
That will look for a label element with an id that ends with 'cat'
If your javascript is in the aspx file, and not a js file, you can also access it like so:
$('#<%=cat.ClientID %>')
That will just inject that long id created by Sharepoint into your js. Key is it needs to reside in the aspx file, not a js file.

ASP.NET Scope of user control for javascript functions

So I have a user control that exists multiple times on a page. From the back end I can call userControl1.someFunction(); and specify which user control I want to call someFunction() for. But if I have a java-script function on the front-end of the user control I can't call it for individual user controls. All I have to do is call javaFunction(), but this doesn't specify which user control I want to call. So this is what I would like to be able to do, clientsideUserControl1.javaFunction(); Is this possible to do? What I have been doing is generating the function name dynamically IE: clientsideUserControl1_javaFunction(), but I feel like there has to be a better way to do this.
usually you can have one function and have it perform it's work on the whole page or you can change it to take a parameter ( a reference to the usercontrol you're interested in )
That way you don't need to have multiple copies of the same javascript function.
So instead of
function CLIENTID_javascriptFunction{
}
You'd have on function at the global level :
function javascriptFunction(id){
}
and call it with the id of the dom object you're interested in. (use ClientID to get the DOM id of the control)
Turns out that in this case it would be better to use a server control instead of a user control. Server controls seem to be a little more complicated to make but they do protect the scope of the javascript functions.
Here is a link that discusses the differences.
http://www.hotscripts.com/forums/asp-net/31174-difference-between-user-control-custom-server-controls.html
one possible solution is this:
function <%= ClientID %>javaFunction()
{
//code here
}
you will have a function declaration for each user control with the client ID of the control plus function name

Problems when assigning values via JavaScript to Asp.net labels and then passing via C# session object

I am assigning variables to asp labels via javascript with a simple innerHTML call
example:
document.getElementById('labelName').innerHTML = parseFloat(var).toFixed(2);
It appears in the label fine, and I am able to continue to manipulate it via javascript.
I then set it up so that that variable is put into a session object via C# codebehind buttonClick event.
example:
protected void btnConfirm_Click ( object sender, EventArgs e )
{
Session["sessionName"] = labelName.Text;
}
The buttonConfirm_Click method fires it Response.Redirects to another page and populates asp labels with the session object via the c# codebehind page_load method.
example:
lblResult.Text = Session["sessionName"].ToString();
When doing this, the label is empty, no errors or 'null'. I have tried to narrow down the issue by trying various things. When I assign the text explicitly in the c# code behind of the first page and the recieve and assign it to the label on the next page, it shows correctly.
example:
Page 1:
Session["sessionName"].ToString() = "Test";
Page 2:
lblResult.Test = Session["sessionResult"].ToString();
I have tried several other things, such as casting the variables in javascript and in the codebehind, and checking to make sure I had runat="server" within each applicable label.
Anyways, is there something here I am missing? Is asp.net unable to detect the changes that javascript has made to the labels? Are there some incompatibility issues when using innerHTML or anything like this that maybe be causing such a thing to occur?
Thanks in advance!
The problem is that the text in a span tag (that is what asp:Label will render) isn't sent in the post to the server and therefore you can't read your changes server side. You'll need to use a input element (hidden field, textbox etc depending on what your ui should look like).

Failing to add controls to a page dynamically

I'm adding a User Control for each record pulled up in a data reader, here's the basic loop:
while (dr.Read())
{
ImageSelect imgSel = new ImageSelect(dr["Name"].ToString());
myPanel.Controls.Add(imgSel);
}
The problem is that there are no controls added to the page, I check the html output and there is my panel, with nothing in it.
I even stepped through the code in the debugger, and verified that myPanel.Controls gets a control added on each loop, with the count being 6, no errors, but then they dont show up on the page.
I've run the above code in the Page_Init and Page_Load events, both with the same result.
EDIT:
Ok so I've switched to using LoadControl("....ascx") to get my control instance, which is now working. But originally I was also passing in data via the controls constructor.. Is this still possible or do I just need to set them via get/sets?
EDIT 2:
Thanks to Freddy for pointing out that the LoadControl has an overload where you CAN pass in constructor params, see accepted answer.
EDIT 3:
After trying this method both with and without the constructor. I have found its better to just use setters for any properties I want the control to have versus trying to use the passed in object array for my constructor.
Update: As Steve pointed out, the overload of LoadControl that uses the type won't take into account the controls in the ascx. This is also mentioned in this answer: Dynamically Loading a UserControl with LoadControl Method (Type, object[]).
As I mentioned before, the get/set are more in line with the asp.net model, so I recommend using that with the LoadControl variation that receives the user control path. That said, the Steve's version is an interesting alternative: http://www.grumpydev.com/2009/01/05/passing-parameters-using-loadcontrol/.
My take is the LoadControl with type is meant to be used with web custom controls instead.
If it is an user control you should use LoadControl(usercontrolpath) to get the instance of the user control.
You can use a constructor by doing:
var name = dr["Name"].ToString();
var imgSel = LoadControl(typeof(ImageSelect), new object[]{ name });
myPanel.Controls.Add(imgSel);
Notice that depending on the project model you are using, you need to add a Reference to the aspx to use it with the typeof variation:
<%# Reference Control="~/somepath/myusercontrol.ascx" %>
Ps. I usually use the set/get for controls as I find them more in line with the asp.net model
To add UserControls you must call the LoadControl method passing in the path to the .ascx file. You can not create them by just instantiating the object the .ascx file inherits from.
A UserControl consists of both the markup and the class in the code behind. The markup contains a link to the class behind, but the class behind does not know where the markup lives and therefore can not be created on it's own.

Trying to set/get a JavaScript variable in an ActiveX WebBrowser from C#

We have a windows application that contains an ActiveX WebBrowser control. As part of the regular operation of this application modifications are made to the pages that are displayed by the ActiveX WebBrowser control. Part of these modifications involve setting a JavaScript variable in a web page being loaded into the ActiveX WebBrowser.
We need to initialize this variable within C# (originally, VB6 code was initializing the value). The value of this variable is a COM-visible class object.
However, for simplicity we've reduced the problem to setting a string value. Our original page involves frames and the like but the same problems happens in a page like this:
<HTML>
<HEAD>
<TITLE>Test</TITLE>
<SCRIPT type="text/javascript">
var field = 'hello world';
</SCRIPT>
</HEAD>
<BODY>
<input type="button" value="See field" onclick="javascript:alert(field);"/>
</BODY>
</HTML>
We want to access the field variable and assign a value to it. In VB6 the code for this was pretty straightforward:
doc.Script.field = 'newValue'
However, in C# we've had to resort to other tricks, like this:
Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateSet(Script, null, "field",new object[] { "newValue"},null, null);
The point of the page is to test whether our variable was properly assigned by C#. Clicking on the button should yield whatever new value was injected by C#. So for example, clicking on the button in the page we get an alert showing: "newValue".
That works the first time, but it doesn't work if we reload the page. On subsequent calls we cannot set the value of the variable field.
Has anyone had any experience doing this type of operation before?
I think what you are looking for is the eval() method in Javascript. You can call it from C# like this:
webBrowser1.Document.InvokeScript("eval", new String[] {"1 + 2"});
This code will evaluate "1 + 2" and return "3". I would imagine that if you were to put in
InvokeScript("eval", new String[] {"varName = 3"})
you would get that variable assigned to 3 if it is globally visible in the file.
If you use the webBrowser control, you can assign a c# object to the
objectForScripting property
http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.objectforscripting.aspx
after that you can use window.external in your javascript to interact with your c# object from javascript
if you use an activeX version for some reason, you can pass javascript: urls to programmatically sets your variable, or you can syncronize your script using a webservice/ database/file or simply using the method you suggested.
These two articles helped us find a solution to our problem. They outline the basics of what one needs to know:
Microsoft Web Browser Automation using C#
Using MSHTML Advanced Hosting Interfaces
So we implemented a DocHostUIHandler interface and that allowed us to set a UIHandler, allowing us to reference the method from Javascript.
The usual method we use is to add a hidden text input box (the ASP.Net control version) on the page. That way you can easily set its value in the C# codebehind and read the value in client side JavaScript (and vice-versa, of course).

Categories