B_D
B_D

Reputation: 235

Partial refresh in ASP using ajax

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);
    }

Upvotes: 0

Views: 612

Answers (2)

B_D
B_D

Reputation: 235

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

Upvotes: 0

Jasen
Jasen

Reputation: 14250

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);
    });

Upvotes: 1

Related Questions