TRock
TRock

Reputation: 189

Asp.Net Core 2.0 MVC Issue with jQuery ready function

Let me start off by saying that I an new to Core 2.0 as well as MVC so please forgive my ignorance

I have used webforms for many years and would use AJAX to handle this, but I have had a hard time finding the answer for MVC.

I believe the issue I am having is that when I click the button on the page, that it is doing a full post and not using Ajax to partially post. The only reason this makes a difference is that on this login screen I have the login form fly down on page load.

<script type="text/javascript">
    $().ready(function () {
        setTimeout(function () { $('.card').removeClass('card-hidden'); }, 700)
    });
</script>

If the user were to enter incorrect information and I have to display an error, the login form will once again fly in from the top.

So my question is two fold.

  1. For starters is there any easy way to stop it from floating in on a postback? With webforms I could access the HTML directly in the code behind and remove the class before I return. Maybe I could do something like adding a state to my ViewModel and then I could switch the class based on that in Razer.

  2. Alternatively it would be nice to be able to use AJAX like I am able to do in webforms as I am sure I will have additional more complex UI issues associated with page loading and current status of elements. Does anyone know of a good resource for this?

RECAP

Solution

First off a big thanks to David Lang for pointing me in the right direction. Between his post and the link I was able to work this out.

A word of caution, much of my issues were caused by a nuget package not installing correctly. The Microsoft unobtrusive Ajax installed, but because I didn't have a folder called scripts, it never put the JS files in my project. Once I got those in my project the rest became easier.

Upvotes: 0

Views: 2470

Answers (1)

David Liang
David Liang

Reputation: 21476

Since you're new to ASP.NET Core 2.0, I am not going to explain things in details but I very want to encourage you to go research them and later on master them by yourself.

Regular Form Post

LoginViewModel.cs

namespace DL.SO.Project.Reporting.Accounts
{
    public class LoginViewModel
    {
        [Required]
        public string Username { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }

        [Display(Name = "Remember my login?")]
        public bool RememberMe { get; set; }

        public string ReturnUrl { get; set; }
    }
}

Login.cshtml

@model DL.SO.Project.Reporting.Accounts.LoginViewModel
@{
    ViewBag.Title = "Login";
    Layout = "~/Views/Shared/_CenteredLayout.cshtml";
}

<div class="widget">
    <form asp-area="" asp-controller="account" asp-action="login">
        <input type="hidden" asp-for="ReturnUrl" />

        <div asp-validation-summary="ModelOnly" class="text-danger"></div>

        <div class="form-group">
            <label asp-for="Username" class="required"></label>
            <input type="text" class="form-control" asp-for="Username" autofocus="autofocus" />
            <span class="form-text" asp-validation-for="Username"></span>
        </div>
        <div class="form-group">
            <label asp-for="Password" class="required"></label>
            <input type="password" class="form-control" asp-for="Password" autocomplete="off" />
            <span class="form-text" asp-validation-for="Password"></span>
        </div>
        <div class="form-check">
            <label class="custom-control custom-checkbox">
                <input type="checkbox" class="custom-control-input" asp-for="RememberMe" />
                <span class="custom-control-indicator"></span>
                <span class="custom-control-description">
                    @Html.DisplayNameFor(m => m.RememberMe)
                </span>
            </label>
        </div>
        <button type="submit" class="btn btn-primary btn-block">Login</button>
    </form>
</div>

See the asp-controller on the form element, and those asp- attributes on inputs? They're built-in tag helpers from ASP.NET Core.

For example, with asp- attributes on form element, it will create a form with POST method attribute and action attribute pointing to /account/login. And hopefully you have an Account controller Login method to handle that request.

Optional: for client side validation to work, you need jquery-validation and jquery-validation-unobtrusive packages.

Ajax Form Post

To use AJAX for the form post, there are some additional steps beside building forms like above.

  • Need to install package jquery-ajax-unobtrusive.
  • Need to specify ajax callbacks using data- on the form element.
  • Need to define the callback functions.

For example,

<form asp-area="" asp-controller="account", asp-action="login"
    data-ajax="true" data-ajax-method="post" data-ajax-begin="onFormBegin"
    data-ajax-complete="onFormComplete">
...
</form>

For a complete list of Unobtrusive ajax helpers, please see here: https://dotnetthoughts.net/jquery-unobtrusive-ajax-helpers-in-aspnet-core/

And then you need to define the callback functions.

@section scripts {
    <script type="text/javascripts">
        $(function() {
            window.onFormBegin = function() {
                ...
            };

            window.onFormComplete = function(request, status) {
                ...

                // if the status is not valid
                //     keep displaying the form?
                // just an idea...

                ...
            };
        });
    </script>
}

My Taste

This is just my opinion. Whenever I deal with account login and other security related stuff, I tend to use regular form post instead of ajax. I don't want anything fancy there, because when something goes wrong, I want the server to give the user a fresh page, or redirect user to somewhere directly and immediately, instead of keeping the page that has invalid information and using ajax to communicate.

Again this is just my personal taste.

Upvotes: 1

Related Questions