18

Can I call javascript function from MVC controller action (not from view page) and get return value? How?


I need to make request to server from code (.cs) using javascript like here (but this is aspx page)

function getInitData() { 
var code; code = 'return {' ;
code += 'me: API.getProfiles({uids: API.getVariable({key: 1280}), fields: "photo"})[0]'; 
code += '};'
VK.Api.call('execute', { 'code': code }, onGetInitData); 
} 
tereško
  • 58,060
  • 25
  • 98
  • 150

9 Answers9

27

For those that just used a standard form submit (non-AJAX), there's another way to fire some Javascript/JQuery code upon completion of your action.

First, create a string property on your Model.

public class MyModel 
{
    public string JavascriptToRun { get; set;}
}

Now, bind to your new model property in the Javascript of your view:

<script type="text/javascript">
     @Model.JavascriptToRun
</script>

Now, also in your view, create a Javascript function that does whatever you need to do:

<script type="text/javascript">
     @Model.JavascriptToRun

     function ShowErrorPopup() {
          alert('Sorry, we could not process your order.');
     }

</script>

Finally, in your controller action, you need to call this new Javascript function:

[HttpPost]
public ActionResult PurchaseCart(MyModel model)
{
    // Do something useful
    ...

    if (success == false)
    {
        model.JavascriptToRun= "ShowErrorPopup()";
        return View(model);
    }
    else
        return RedirectToAction("Success");
}
Jason Marsell
  • 1,752
  • 2
  • 19
  • 10
14

You can call a controller action from a JavaScript function but not vice-versa. How would the server know which client to target? The server simply responds to requests.

An example of calling a controller action from JavaScript (using the jQuery JavaScript library) in the response sent to the client.

$.ajax({
           type: "POST",
           url: "/Controller/Action", // the URL of the controller action method
           data: null, // optional data
           success: function(result) {
                // do something with result
           },                
           error : function(req, status, error) {
                // do something with error   
           }
       });
Russ Cam
  • 124,184
  • 33
  • 204
  • 266
  • I need to make request to server from code using javascript like here: function getInitData() { var code; code = 'return {' ; code += 'me: API.getProfiles({uids: API.getVariable({key: 1280}), fields: "photo"})[0]'; code += '};'; VK.Api.call('execute', { 'code': code }, onGetInitData); } –  Apr 26 '10 at 06:11
  • Hi Russ, I'm having a large no of commandButtons(binding to same action) under a list of 20 items. Thus I'm trying to reduce the no of commandButtons. I was looking at ways to call action methods in controller classes through javascript & just came across this. Should I use your given techinque to reduce the state by calling action methods though like this from JS instead of multiple commandButtons approach ? Thanks ! – Rajat Gupta Nov 20 '11 at 20:46
  • @Marcos - I'm not sure I fully understand what your question is - I'd recommend opening a new question with the details and see how the stackoverflow community can help – Russ Cam Nov 20 '11 at 21:55
  • Thanks. Already did that http://stackoverflow.com/questions/8204545/call-action-methods-in-controller-managed-beans-through-javascript – Rajat Gupta Nov 21 '11 at 04:17
  • 1
    What about SignalR? Or Long Polling / Web Sockets in general? Wouldn't that provide the effect? – Ivy Aug 10 '12 at 17:02
  • @Devon - Long Polling is done via AJAX so is still initiated by the client via polling. I can't speak with any authority on Web Sockets, Server Sent Events or Forever Frame (the other transports used by SignalR). From my limited knowledge of them, all three can initiate a push to a client once a connection is established with the client. Am happy to update the answer or for someone else to update the answer who has definitive knowledge on this. – Russ Cam Aug 10 '12 at 18:58
  • You can use RegisterClientScriptBlock to register client side JS on load. – Beau D'Amore Apr 22 '15 at 16:12
  • @Beau yes you can, in web forms. That is still the client calling the server. – Russ Cam Apr 22 '15 at 20:55
  • http://stackoverflow.com/questions/7271005/asp-net-mvc-returning-javascriptresult-doesnt-work Carl Hancke answer ? – cah1r Apr 28 '16 at 12:20
  • @MateuszMigała again, still the client calling the server via JavaScript sent from the server – Russ Cam Apr 28 '16 at 12:25
12

Yes, it is definitely possible using Javascript Result:

return JavaScript("Callback()");

Javascript should be referenced by your view:

function Callback(){
    // do something where you can call an action method in controller to pass some data via AJAX() request
}
Arman H
  • 5,488
  • 10
  • 51
  • 76
Dhanasekar Murugesan
  • 3,141
  • 1
  • 18
  • 21
4

It is late answer but can be useful for others. In view use ViewBag as following:

@Html.Raw("<script>" + ViewBag.DynamicScripts + "</script>")

Then from controller set this ViewBag as follows:

ViewBag.DynamicScripts = "javascriptFun()";

This will execute JavaScript function. But this function would not execute if it is ajax call. To call JavaScript function from ajax call back, return two values from controller and write success function in ajax callback as following:

$.ajax({
       type: "POST",
       url: "/Controller/Action", // the URL of the controller action method
       data: null, // optional data
       success: function(result) {
            // do something with result
       },
     success: function(result, para) {
        if(para == 'something'){
            //run JavaScript function
        }
      },                
       error : function(req, status, error) {
            // do something with error   
       }
   });

from controller you can return two values as following:

return Json(new { json = jr.Data, value2 = "value2" });
1

If I understand correctly the question, you want to have a JavaScript code in your Controller. (Your question is clear enough, but the voted and accepted answers are throwing some doubt) So: you can do this by using the .NET's System.Windows.Forms.WebBrowser control to execute javascript code, and everything that a browser can do. It requires reference to System.Windows.Forms though, and the interaction is somewhat "old school". E.g:

void webBrowser1_DocumentCompleted(object sender, 
    WebBrowserDocumentCompletedEventArgs e)
{
    HtmlElement search = webBrowser1.Document.GetElementById("searchInput");
    if(search != null)
    {
        search.SetAttribute("value", "Superman");
        foreach(HtmlElement ele in search.Parent.Children)
        {
            if (ele.TagName.ToLower() == "input" && ele.Name.ToLower() == "go")
            {
                ele.InvokeMember("click");
                break;
            }
        }
    }
}

So probably nowadays, that would not be the easiest solution.

The other option is to use Javascript .NET or jint to run javasctipt, or another solution, based on the specific case.

Some related questions on this topic or possible duplicates:

Embedding JavaScript engine into .NET

Load a DOM and Execute javascript, server side, with .Net

Hope this helps.

Community
  • 1
  • 1
d.popov
  • 4,175
  • 1
  • 36
  • 47
1

There are ways you can mimic this by having your controller return a piece of data, which your view can then translate into a JavaScript call.

We do something like this to allow people to use RESTful URLs to share their jquery-rendered workspace view.

In our case we pass a list of components which need to be rendered and use Razor to translate these back into jquery calls.

Jon Eastwood
  • 813
  • 10
  • 22
0

The usual/standard way in MVC is that you should put/call your all display, UI, CSS and Javascript in View, however there is no rule to it, you can call it in the Controller as well if you manage to do so (something i don't see the possibility of).

Sarfraz
  • 377,238
  • 77
  • 533
  • 578
0

Since your controller actions execute on the server, and JavaScript (usually) executes on the client (browser), this doesn't make sense. If you need some action to happen by default once the page is loaded into the browser, you can use JavaScript's document.OnLoad event handler.

3Dave
  • 28,657
  • 18
  • 88
  • 151
0
<script>
    $(document).ready(function () {
        var msg = '@ViewBag.ErrorMessage'
        if (msg.length > 0)
            OnFailure('Register', msg);
    });

    function OnSuccess(header,Message) {
        $("#Message_Header").text(header);
        $("#Message_Text").text(Message);
        $('#MessageDialog').modal('show');
    }

    function OnFailure(header,error)
    {
        $("#Message_Header").text(header);
        $("#Message_Text").text(error);
        $('#MessageDialog').modal('show');
    }
</script>
Farshad
  • 1
  • 2