Reputation: 18724
I have a layout page which is used by my MVC site. It has no models or any related controller methods.
But now I want to add a "Search" box at the top. I can't add a normal "Form" because it get's over ridden, or overrides any other forms on the content pages. So I was thinking I might have to do it with Javascript... call a javascript function that then sends the query to a controller, and then moves the user to the result screen.
Is this the right way to do it? Or can I somehow use a normal controller method call from my layout page?
Upvotes: 0
Views: 83
Reputation: 21231
Let's assume you have these models:
public class SearchModel
{
public string SearchTerm { get; set; }
}
public class LoginModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
And that you also had these controllers:
public class HomeController : Controller
{
public ActionResult Search(SearchModel model)
{
return View();
}
}
public class AccountController : Controller
{
public ActionResult Login(LoginModel model)
{
return View();
}
}
You could use something like this as a layout view:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewBag.Title</title>
</head>
<body>
@using(Html.BeginForm("search", "home", FormMethod.Post, new {}))
{
<input type="search" name="SearchTerm" placeholder="Find..." />
<button type="submit">GO</button>
}
@if(!Request.IsAuthenticated)
{
using(Html.BeginForm("login", "account", FormMethod.Post, new {}))
{
<input type="text" name="UserName" placeholder="..." />
<input type="password" name="Password" placeholder="..." />
<button type="submit">GO</button>
}
}
@RenderBody()
</body>
</html>
The model binder is smart enough to match up request parameters to the correct model properties, even if you don't use the @Html
helpers to create your HTML controls. The problem you'll run into is what to do with, say, invalid login attempts. Seems like the typical workflow is to have a normal login action - that lets you dump the user to a proper login page if they enter invalid credentials in, say, a navbar login form.
Another option is to embed the search and login forms as child actions:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewBag.Title</title>
</head>
<body>
@Html.Action("search", "home")
@Html.Action("login", "account")
@RenderBody()
</body>
</html>
If you go that route, you would modify the controller to return partial views. Here's one implementation of an AccountController:
public class AccountController : Controller
{
[HttpGet, AllowAnonymous]
public ActionResult Login(string returnUrl = "")
{
return View();
}
[HttpPost, AllowAnonymous]
public ActionResult Login(LoginModel model)
{
if(ModelState.IsValid)
{
/* valid user credentials */
return RedirectToAction("index", "home");
}
return View(model);
}
[AllowAnonymous, ChildActionOnly]
public ActionResult NavbarLogin()
{
return PartialView();
}
}
Notice the last action method; marking it as ChildActionOnly
prevents the action from being directly requested by the browser. The view for that method might look like this:
@model Your.Fully.Qualified.Namespace.Models.LoginModel
@using(Html.BeginForm("login", "account", FormMethod.Post, new { }))
{
@Html.LabelFor(m => m.UserName)
@Html.TextBoxFor(m => m.UserName)
@Html.ValidationMessageFor(m => m.UserName)
@Html.LabelFor(m => m.Password)
@Html.PasswordFor(m => m.Password)
@Html.ValidationMessageFor(m => m.Password)
<button type="submit">Login</button>
}
The advantage of the strongly-typed helpers is that MVC will create the validation data-
attributes that the Unobtrusive Validation library leverages; include the jqueryval bundle on the layout and any view with strongly-typed helpers gets client-side validation automatically.
In this example, the "navbar login" posts to the normal login action, so invalid credentials will result in the user being shown the login page, rather than the page they were originally viewing.
Upvotes: 2