I have a web page with JavaScript that calls C# methods using jQuery and AJAX. This works fine. I would like to know how to call JavaScript functions from the C# code, if this is even possible. If it's not possible, is there a sane alternative?
2 Answers
Assuming the browser initiates the interaction
In general, your server-side C# code will respond to interactions initiated by your client-side code. If you're looking for ways your C# code can initiate the interaction in the absense of a browser request, see the next section below.
If you're processing a full page response, then of course you can just output script tags containing the call you want to have occur. Make sure that the script is making the call after the function it's calling has already been defined by an earlier script tag, and if there's going to be DOM interaction be sure to put that script at the bottom of the page (or use jQuery's ready feature).
Responding to Ajax calls, it's possible for the C# code to return strings containing JavaScript code, which your in-page code would then execute (e.g., via eval or similar), but it's generally best to avoid that.
Instead, have the C# code return data in response to an Ajax call, and have your in-page code respond to that data by calling the appropriate function.
A bit of a hybrid of the two is to have your C# code return data that indicates what function to call and what arguments to supply to it, and to have a map of your functions that you index into with the function name, e.g.:
var functions = {
foo: function(arg0, arg1) {
alert("foo called with " + arg0 + "," + arg1);
},
bar: function(arg) {
alert("bar called with " + arg);
}
};
$.ajax({
url: "/path/to/resource",
dataType: "json",
success: function(data) {
if (data && data.fname && data.args) {
functions[data.fname].apply(undefined, data.args);
}
}
});
There, your C# code would return a string containing information encoded in JSON as an object with an fname property (a string giving a function name) and an args property (an array of arguments to pass to the function), which jQuery will deserialize into an object for you. Then we look up the function object in the map using its name (functions[data.fname]) and use the built-in Function#apply to call it and pass in the arguments. That works because you can refer to JavaScript object properties using either dotted syntax and a literal for the property name (obj.propName = 42), or using bracketed syntax and a string for the property name (obj["propName"] = 42), where in the latter example the string can be any expression, including a variable or property reference (name = "propName"; obj[name] = 42;) — which is how we're looking the functions up on the functions map.
I'm not suggesting you do that, just saying it's possible.
If you're trying to have the server initiate the interaction
If you want the server to reach out to the browser instead, you'll have to have some channel of communication established between them, either using the new (and variously supported) web sockets API, or various Comet techniques.
3 Comments
I would like to know how to call JavaScript functions from the C# code, if this is even possible. If it's not possible, is there a sane alternative? He called C# code by JS/Ajax, now he is looking for reverse way!eval-ing them), that the sane alternative is to return data and respond to that, and that there's a hybrid option. All of those require that the browser initiate the interaction, of course; without web sockets or comet techniques, that's always going to be true.Javascript function can not called directly from C#, rather Javascript function/code block can register with page from C# code behind which is called after render or called when it is necessary.
//Register Script block for JS code
Page.ClientScript.RegisterClientScriptBlock(GetType(), "ScriptBlockKey",
"<script> alert('JS alert written in C# code behind.');</script>", false);
//Register Script block for calling JS function
Page.ClientScript.RegisterClientScriptBlock(GetType(), "ScriptBlockKey",
"SomeJSFunction();</script>", false);