0

How do you do a partial refresh of a page using Ajax in cshtml?

As I understand it, Ajax is required. In my scenario, in my index page I have a table where each row has a program (a batch file) and a Run button. Beneath the table I have the a space for the program output. I would like this to populate (I'm happy to wait for the program to finish just now) without having to refresh the rest of the page.

Code is below, but in summary I have one model for the table data, one model for the selected program log/output. The controller for the index page creates both and passes them in to a view model, which is passed to the view. When the Run button is hit an Index overload method in the controller handles the running of the program and 'getting' the output. It also populates the appropriate model in the VM (possibly not ideal and I'm open to suggestions to improve it).

The overloaded method currently returns a PartialViewResult and the output/logging has it's own PartialView (as I'll want to reuse it elsewhere). This is also why it has a separate model. In the PartialView break points are hit, but it doesn't appear on the page in the browser.

I'm using ASP.NET-MVC-4 with Razor.

View (Index.cshtml)

<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
@model ViewModels.UpdateTestViewModel
@{ ViewBag.Title = "Update Test"; }
@{
    <table>
        @* Headers *@
        <tr>
            <td>Programs</td>
        </tr>

        @* Data *@
        <tr>
            <td>@Model.ProgramName</td>
            <td style="min-width:75px"><input id="btnRun" type="button" value="Run" /></td>
        </tr>
    </table>

    <div id="log">
        @Html.Partial("ScriptLog", Model.Log)
    </div>

    <script>
        $("input[type=button]").on("click", function () {
            var NAME = ($(this).parent().siblings(":first")).text();
            $.post("/UpdateTest/Run", { input: NAME });
        });
    </script>
}

Partial View

@model Models.ScriptLog
@if (Model != null && Model.Log.Any(x => !string.IsNullOrWhiteSpace(x)))
{
    <fieldset>
        <legend>Log</legend>
        @foreach (string entry in Model.Log)
        {
            <p>@entry</p>
        }
     </fieldset>
}

Script Log

public IEnumerable<string> Log { get { // returns log } }

ViewModel

public class UpdateTestViewModel
{
    public string ProgramName { get { return "My Program"; } }

    public ScriptLog Log { get { return _log; } }
    private readonly ScriptLog _log;

    public UpdateTestViewModel(ScriptLog log)
    {
        _log = log;
    }
}

Controller

    public ActionResult Index()
    {
        if (SessionFacade.CurrentUpdateTestLog == null)
        {
            ScriptLog log = new ScriptLog();
            SessionFacade.CurrentUpdateTestLog = log; // Store in Session
        }

        UpdateTestViewModel vm = new UpdateTestViewModel(SessionFacade.CurrentUpdateTestLog);

        return View(vm);
    }

    [ActionName("Run")]
    public PartialViewResult Index(string input)
    {
        ExecuteScript.ExecuteUpdateTestScript(input); // Run batch file
        UpdateTestLog(input); // Get log and update in Session

        return PartialView("ScriptLog", SessionFacade.CurrentUpdateTestLog);
    }

2 Answers 2

1

Since you are making an $.post() you need to decorate your /UpdateTest/Run action with [HttpPost].

You also don't define a success handler so, while you are making the request, you never do anything with it.

$.post("/UpdateTest/Run", { input: NAME })
    .done(function(partialResult) {
        $("#log").html(partialResult);
    })
    .fail(function(jqxhr, status, error) {
        console.log(jqXhr, status, error);
    });
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks @Jasen, your ajax code fixed it. I also realised that I wasn't updating the VM with the log results, so I fixed that too. Curiously I didn't need the HttpPost attribute, but I've added it in anyway.
Sorry I spoke too soon, the update isn't working. I was hitting F5 an extra time for the breakpoints and accidentally refreshing the entire page. At this point the log is present and so it is displayed. I also tried adding an alert(...) before the $("#log") line and I never see the alert, it's as if it isn't even getting into the Ajax
Then you need to check the error handler and the browser's network monitor to get more information about the error.
From what I can see it isn't even getting in to the ajax, by adding to the ajax .always(function () { alert(NAME) }) which doesn't produce an alert ever. (Sorry for the delay in updating - I was on holiday)
Is any of this embedded in a form? If so, you'll need to prevent the default submission. Watch the requests with the network monitor and check the headers to see that you're sending a XMLHttpRequest (AJAX).
|
0

With much help and patience from @Jasen I got a working solution which was to extend the existing Ajax, so that it looks like:

$("input[type=button]").on("click", function () {
    var NAME = ($(this).parent().siblings(":first")).text();
    $.post("/UpdateTest/Run", { input: NAME })

    .done(function (partialResult) {
        $("#log").html(partialResult);
    })
});

Note I also have added the [HttpPost] attribute in the controller

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.