How do you create a client-side API for an ASP.NET User Control?
For example: I have a user control, let's call it "MyControl1" and I want to create "Show()" and "Hide()" javascript functions that can be called from javascript on the parent page - something like "MyControl1.Show();"
Obviously there could be multiple controls on the page, so if you had dropped 2 controls on page:
<MyTag:MyControl ID="MyControl1" runat="server" />
<MyTag:MyControl ID="MyControl2" runat="server" />
It would be nice to be able to do something like:
function ParentPageJavascriptFunction(){
MyControl1.Show();
MyControl2.Hide();
}
How do I go about doing this? Every article I find is about how to hook events in a user control, and I just want the parent page to be able to call certain functions as it sees fit - or perhaps there is a way to use events to do what I am trying to do and I just don't understand it.
Edit: This doesn't seem to be coming across correctly, how about this...
This is what my hypothetical control looks like:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="controls_MyControl" %>
<script type="text/javascript">
function Display(msg) {
var Label1ClientID = '<%= Label1.ClientID %>';
document.getElementById(Label1ClientID)... (display the message)
}
</script>
<asp:Label ID="Label1" runat="server"> </asp:Label>
Now, the "parent" page registers the control like this:
<%@ Register Src="~/controls/MyControl.ascx" TagName="MyControl" TagPrefix="MyTag" %>
And in the body it has this:
<asp:Button ID="MyButton1" runat="server" Text="Display" OnClientClick="javascript:MyControl1.Display('hello'); return false;" />
<MyTag:MyControl Id="MyControl1" runat="server">
</MyTag:MyControl>
The only problem is, obvi开发者_开发技巧ously, that doesn't work - but that's what I am trying to get at. How do you make this work? I want to be able to allow the page that the user control is nested inside of (the parent page) to be able to call the Display function of that user control. I realize that you can just call Display because its just js (whether it's in the User Control or not), but if you had 2 of these controls on that page that wouldn't work, so how do you create javascript such that the parent page can differentiate which User Controls function it wants to call?
What your trying to do is pretty straightforward. The asp.net controls are a bulky way of wrapping pure html into controls on a page. In order to be able to call a javascript event on a control you have to know the ID of the result of the control rendering to the page.
NOTE: all .net controls have a member called .ClientID and this represents what the runtime will generate as the ID of the HTML it is designed to encapsulate/render.
In order to get the ID of the control on the page when it renders you need to do something like this:
var dotNetHtmlClientID = '<%= txtMessage.ClientID %>';
$('#' + dotNetHtmlClientID).bind('onclick', function(){
//dostuff
});
The first line is c# inline code to get the ClientID from the runtime.
Update **
If you want to get the clientID of the user control from the page that it is located on you need to do this:
//on the dot net page server side
protected string controlClientId;
void Page_Load(object sender, Eventargs e)
{
controlClientId = Page.FindControl("MyControlThatImBindingEventToDotNetId").ClientID;
}
//on the page client side
var dotNetHtmlClientID = '<%= controlClientId %>';
$('#' + dotNetHtmlClientID).bind('onclick', function(){
//dostuff
});
One way you could approach this problem is to create a module in javascript. In short, that means you might have xyzClientApi.js
that contains some set of functions that enhance functionality on the page.
Inside of that file, you would create an object that has references to the controls that you're interested in scripting functionality onto. In javascript, you nest variables or objects inside of functions to effectively namespace them (this will reduce collisions between your javascript and other bits of javascript that might be in use).
This function will create a scope for your client side api:
// this is the variable that you'll reference from your view markup
// the style shown here is a self executing anonymous function.
// sounds scarier than it is! don't be afraid.
var xyzClientApi = (function($) {
// this is the object that will be assigned to xyzClientApi.
// the {} in this line is just an object initializer
// you can put things inside of it using this syntax: <name>:<value>
var model = {};
// you can use an init() function to accept parameters
// when you initialize the api.
// i.e. xyzClientApi.init({myUserControl:'#myUserControl1', myButton:'#myButton1'});
model.init = function(params) {
// add properties and functions to your model
// based on parameters in here
model.myUserControl = {
display: function(text) {
$(params.myUserControl).val(text);
}
};
// assign a click handler to your button!
$(params.myButton).click(function(){
model.myUserControl.display('hello!');
});
};
// remember to return model!
return model;
// by passing jQuery here, the '$' parameter
// is guaranteed to be jQuery when you use it
// this is to play nice with other js libraries
// that might also use '$' at the global scope.
})(jQuery);
Then, you'll be able to use this in your markup:
<script type="text/javascript" src="xyzClientApi.js"></script>
<script type="text/javascript">
// standard jQuery DOM ready function
$().ready(function(){
// call the init from above
// this is using the object initializer syntax in javascript
// it's just a nice way of grouping your parameters
// each property of the object is declared, followed by a colon,
// which is followed by a value. this value can be any valid javascript
// object, like a string, value, or some other object.
// in this case, we're passing the known control IDs in.
xyzClientApi.init({
myUserControl: '<%= MyUserControlClientID %>',
myButton: '<%= MyButtonControlClientID %>'
});
});
</script>
If you don't know the ID of your control, or you can't reasonably determine what it would be, try wrapping it in a div or some other html element:
<div id="MyControlIsInhere">...your control...</div>
Then you'd use a selector like this:
'#MyControlIsInHere input[type=button]'
My solution involves you adding a wrapper div inside your user control and then using jQuery to extend it - adding whatever clientside methods and properties you wish. The trick is to set the wrapper div's ID to be the same as the User Control's using like id='<%= this.ID %>'
.
The User Control itself doesn't actually render anything (only contents), so the div just gives you an object with an ID you can reference back on your containing page (because you know the User Control's ID there). And with your properties/methods extended off the div, everything is neatly scoped (nothing in the global namespace) and you can simply grab an object reference using the User Control's ID with a standard $get('myUcWhatever')
- and you're good to go.
I have a full explanation and demo solution posted on my blog if you want more details: http://programmerramblings.blogspot.com/2011/07/clientside-api-for-aspnet-user-controls.html
精彩评论