Hank
Hank

Reputation: 2616

Adding partial view via ajax

In my main layout I'm trying to add a login partial view via ajax, however I keep getting 'Internal Server Error'. I've tried various other posted solutions without luck

Everything is pretty standard I've got my HomeController and index.cshtml (which uses layout.cshtml)

In the layout, once the document is ready, I use ajax to see if a user is logged in via the HomeController, if the returned value is false I want to show a partial view.

The function showLoginPartial where it trys, via ajax, to get the partial view from the LoginController fails

"Error in showLoginPartial(): Internal Server Error :-: error"

What am I doing wrong?

HomeController method:

    public JsonResult IsUserLoggedIn()
    {
        return Json(new { result = (CurrentUser != null) }, JsonRequestBehavior.AllowGet);
    }

layout jquery:

$(document).ready(function () {
    checkLoggedIn();
    function checkLoggedIn() {
        $.ajax({
            url: '@Url.Action("IsUserLoggedIn", "Home", new { })',
            success: function (data) {
                if (data.result == false) {
                    //Show the login partial view
                    showLoginPartial();
                }
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                alert("Error in checkLoggedIn(): " + errorThrown + " :-: " + textStatus);
            }
        });
    }

    function showLoginPartial() {
        $.ajax({
            url: '@Url.Action("LoginDisplay", "Login", new { })',
            success: function (response) {
                //add the partial view after #ib-container div
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                //Error displays
                alert("Error in showLoginPartial(): " + errorThrown + " :-: " + textStatus);
            }
        });
    }
})

LoginController:

public class LoginController : Controller
{
    // GET: Login
    [ChildActionOnly]
    public ActionResult LoginDisplay()
    {
        return PartialView("_LoginDisplay");
    }
    public JsonResult UserLoggedOut()
    {
        return Json(new { result = Nuclei.Models.CurrentUserAccount.Instance.LoggedOut }, JsonRequestBehavior.AllowGet);
    }

    public JsonResult UserAutoAuthenticate()
    {
        bool l_result = false;
        System.Threading.Thread.Sleep(3000);
        return Json(new { result = l_result }, JsonRequestBehavior.AllowGet);
    }

    public JsonResult UserManualAuthenticate()
    {
        bool l_result = false;
        System.Threading.Thread.Sleep(3000);
        return Json(new { result = l_result }, JsonRequestBehavior.AllowGet);
    }

    public JsonResult SendUserCredentials()
    {
        bool l_result = true;
        System.Threading.Thread.Sleep(3000);
        return Json(new { result = l_result }, JsonRequestBehavior.AllowGet);
    }
}

Site Structure: enter image description here

[EDIT]

Just tried adding the partial view via an RenderAction() and it worked, but this is not what I'm after, definitely want to use ajax.

@{ Html.RenderAction("LoginDisplay", "Login"); }

Added the rest of the methods into the LoginController above as well

_LoginDisplay.cshtml

<div id="login_layer_overlay">
</div>

<div id="login_layer">

    <div id="MainLoginDiv">
        <div id="LoginHeaderDiv" class="text-center">
            <h3 id="LoginHeader" class="page-header" style="color:white;">&nbsp;</h3>
        </div>
        <div id="Spinner" class="spinner">
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
            <i><b></b></i><!--1--><i><b></b></i><!--2--><i><b></b></i><!--3--><i><b></b></i><!--4--><i><b></b></i><!--5--><i><b></b></i><!--6--><i><b></b></i><!--7--><i><b></b></i><!--8--><i><b></b></i><!--9--><i><b></b></i><!--10-->
        </div>
        <div id="ManualLogin" class="box" style="border: none;">
            @using (Html.BeginForm())
            {
                @Html.AntiForgeryToken()
                <div class="form-group">
                    <label class="control-label" style="color:white;">Username</label>
                    @Html.TextBox("username", null, new { id = "username", @class = "form-control", @Value="us" })
                </div>
                <div class="form-group">
                    <label class="control-label" style="color:white;">Password</label>
                    @Html.TextBox("password", null, new { id = "password", @class = "form-control", @Value = "pwd" })
                </div>
                <div class="text-center" style="margin-top:40px;">
                    <input type="button" id="ManualLoginBtn" value="Sign in" class="btn btn-primary" />
                    <br />
                    <input type="button" id="AutoLoginBtn" value="Auto Authenticate" class="btn btn-default" />
                    <input type="button" id="ForgotLoginBtn" value="Forgot Credentials" class="btn btn-default" />
                </div>
            }
        </div>
        <div id="ForgotLogin" class="box" style="border: none;">
            @using (Html.BeginForm())
            {
                @Html.AntiForgeryToken()
                <div class="form-group">
                    <label class="control-label" style="color:white;">Email</label>
                    @Html.TextBox("email", null, new { id = "email", @class = "form-control", @Value = "jhjhblah" })
                </div>
                <div class="text-center" style="margin-top:40px;">
                    <input type="button" id="BackToLoginBtn" value="Back" class="btn btn-default" />
                    <input type="button" id="ForgotSubmitBtn" value="Submit" class="btn btn-primary" />
                </div>
            }
        </div>
    </div>
</div>
<script>
    $(document).ready(function () {

        var spinnerItems = $("#Spinner i b");
        $("#MainLoginDiv").css("opacity", "1");
        checkUserLoggedOut();


        function checkUserLoggedOut() {
            $.ajax({
                //First need to check for logged off
                url: '@Url.Action("UserLoggedOut", "Login", new { })',
                success: function (data) {

                    if (data.result == false) {
                        showAutoAuthenticate();
                    }
                    else {
                        showManualForm();
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert("Error: " + errorThrown + " :-: " + textStatus);
                }
            });
        }

        function showAutoAuthenticate() {
            $("#LoginHeader").text("Auto Authenticating");
            $("#ManualLogin").css("opacity", "0");
            setTimeout(function () { $("#ManualLogin").css("display", "none"); }, 550);
            $("#Spinner").css("opacity", "1");

            spinnerItems.each(function () {
                $(this).addClass("spinAnimation");
            })
            $.ajax({
                url: '@Url.Action("UserAutoAuthenticate", "Login", new { })',
                success: function (data) {

                    if (data.result == false) {
                        //Switch to manual
                        //showForgotLogin();
                        showManualForm();
                    }
                    else {
                        //Remove login
                        $("#AutoLogin").css("opacity", "0");
                        spinnerItems.each(function () {
                            $(this).removeClass("spinAnimation");
                        })
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert("Error in showAutoAuthenticate(): " + errorThrown + " :-: " + textStatus);
                }
            });
        }

        function showManualAuthenticate() {
            $("#LoginHeader").text("Authenticating");
            $("#ManualLogin").css("opacity", "0");
            setTimeout(function () { $("#ManualLogin").css("display", "none"); }, 550);
            $("#Spinner").css("opacity", "1");

            spinnerItems.each(function () {
                $(this).addClass("spinAnimation");
            })

            $.ajax({
                url: '@Url.Action("UserManualAuthenticate", "Login", new { })',
                success: function (data) {

                    if (data.result == false) {
                        //Switch to manual
                        //showForgotLogin();
                        showManualForm();
                    }
                    else {
                        //Remove login
                        $("#AutoLogin").css("opacity", "0");
                        spinnerItems.each(function () {
                            $(this).removeClass("spinAnimation");
                        })
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert("Error in showManualAuthenticate(): " + errorThrown + " :-: " + textStatus);
                }
            });
        }

        function showForgottenProcessing() {
            $("#ForgotLogin").css("opacity", "0");
            setTimeout(function () { $("#ForgotLogin").css("display", "none"); }, 550);
            $("#Spinner").css("opacity", "1");

            spinnerItems.each(function () {
                $(this).addClass("spinAnimation");
            })

            $.ajax({
                url: '@Url.Action("SendUserCredentials", "Login", new { })',
                success: function (data) {

                    if (data.result == false) {
                        //Switch to manual
                        showForgotLoginForm();
                    }
                    else {
                        //Go back to login
                        showManualForm();
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert("Error in showManualAuthenticate(): " + errorThrown + " :-: " + textStatus);
                }
            });
        }

        function showManualForm() {

            $("#Spinner").css("opacity", "0");
            spinnerItems.each(function () {
                $(this).removeClass("spinAnimation");
            })
            $("#ForgotLogin").css("opacity", "0");
            setTimeout(function () { $("#ForgotLogin").css("display", "none"); }, 550);

            $("#LoginHeader").text("Login");
            $("#ManualLogin").css("display", "block");
            $("#ManualLogin").css("opacity", "1");
        }

        function showForgotLoginForm() {

            $("#Spinner").css("opacity", "0");
            spinnerItems.each(function () {
                $(this).removeClass("spinAnimation");
            })
            $("#ManualLogin").css("opacity", "0");
            setTimeout(function () { $("#ManualLogin").css("display", "none"); }, 550);

            $("#LoginHeader").text("Retrieve Credentials");
            $("#ForgotLogin").css("display", "block");
            $("#ForgotLogin").css("opacity", "1");
        }

        $("#AutoLoginBtn").click(function () {
            showAutoAuthenticate();
        });
        $("#ForgotLoginBtn").click(function () {
            showForgotLoginForm();
        });
        $("#BackToLoginBtn").click(function () {
            showManualForm();
        });
        $("#ManualLoginBtn").click(function () {
            showManualAuthenticate();
        });
        $("#ForgotSubmitBtn").click(function () {
            showForgottenProcessing();
        });
    })
</script>

Upvotes: 2

Views: 395

Answers (1)

Tetsuya Yamamoto
Tetsuya Yamamoto

Reputation: 24957

The [ChildActionOnly] attribute usage ensures that an action method can be called only as a child method from a parent view (i.e. disables direct navigation to load partial view like /Login/LoginDisplay), and usually used to render partial view with RenderAction() helper:

Any method that is marked with ChildActionOnlyAttribute can be called only with the Action or RenderAction HTML extension methods.

Since you're not calling the partial view by RenderAction() but with AJAX which requires direct URL navigation in url setting, the ChildActionOnlyAttribute immediately prevents respond to request of that URL and runtime error Child action accessible only by a child request will be thrown (shown as "Internal Server Error" in AJAX result).

Hence, the controller action should not use [ChildActionOnly] attribute:

[HttpGet]
public ActionResult LoginDisplay()
{
    return PartialView("_LoginDisplay");
}

And the AJAX call should be like this:

function showLoginPartial() {
    $.ajax({
        url: '@Url.Action("LoginDisplay", "Login")',
        type: 'GET',
        success: function (response) {
            $('#ib-container').html(response);
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
           //Error displays
           alert("Error in showLoginPartial(): " + errorThrown + " :-: " + textStatus);
        }
    });
}

References:

System.Web.Mvc.ChildActionOnlyAttribute Class

Using ChildActionOnly in MVC

Upvotes: 2

Related Questions