Populating Html.ActionLink() with a variable name results in an incomplete href - c#

Due to some unusual requirements I am getting the name of my controller while in my partial view and trying to populate an ActionLink with the controller name, like so:
#{
var controllerName = this.ViewContext.RouteData.Values["controller"].ToString(); // controller name is "Office"
#Html.ActionLink("Login", "Login", controllerName, null, new { #class = "btn btn-primary" })
}
It is generating this HTML:
<a class="btn btn-primary" href="/Office">Login</a>
whereas it should be generating this HTML:
<a class="btn btn-primary" href="/Office/Login">Login</a>
The odd thing is that the link still directs to the Login action in the Office controller. What exactly is going on here?

Related

How to manage multiple submit button in my case in MVC 5?

I am a beginner to MVC, I am using MVC 5
_Layout.cshtml code
_Layout.cshtml has navbar, it contains Logout, More button if user already loggedin, Also, it will render body part(Index.cshtml)
//Navbar
#if (ViewBag.name != null)
{
<input type="submit" class="dropdown-item" formaction="Logout" value="Logout" id="btnLogout" />
}
else{
<a class="nav-link" href="#">Login & Signup</a>
}
<input type="submit" class="dropdown-item" formaction="More" value="More" id="btnMore" />
//body
<div class="container body-content">
#RenderBody() //Index.cshtml
</div>
Index.cshtml
Index.cshtml it has some links and also some buttons and anchor links, and it will call partial view (_Login)
#using TestProject.Models
#model ViewSignInAndSignUp
//some html code
<input type="submit" class="dropdown-item" formaction="Action1" value="Action1" id="btnAction1" />
<input type="submit" class="dropdown-item" formaction="Action2" value="Action1" id="btnAction2" />
#Html.Partial("_Login") //partialview
_Login.cshtml
_Login.cshtml this one partial view, if user visit any links, this partial view will popup to request the user to make login. This partial view buttons are working
#model TestProject.Models.SignIn
#using (Html.BeginForm("ControllerSignIn", "Home"))
{
#Html.TextBoxFor(si => si.userName, new { #class = "form-control", #id = "txtLogin" })
#Html.TextBoxFor(si => si.password, new { #class = "form-control", #id = "txtPassword", #type = "password" })
<input type="submit" class="btn btn-sm btn-primary btn-rounded" value="Login" id="btnLoginSubmit" />
}
HomeController
[HttpPost]
public ActionResult Logout(string submitButton)
{
// some coding
return RedirectToAction("Index", "Home");
}
[HttpPost]
public ActionResult More(string str1)
{
// some coding
return RedirectToAction("Index", "Home");
}
[HttpPost]
public ActionResult Action1(string str1)
{
// some coding
return RedirectToAction("Index", "Home");
}
[HttpPost]
public ActionResult Action2(string str1)
{
// some coding
return RedirectToAction("Index", "Home");
}
Now, How can I manage all the buttons from _Layout.cshtml, Index.cshtml, _Login.cshtml(Partial view)
Note
my login button is working, but, logout, more, action1, action2 buttons are not working
Replace this
<input type="submit" class="dropdown-item" formaction="Logout" value="Logout" id="btnLogout" />
with this
Logout
Replace the href with the logout endpoint for your application if different than stated above. Remove any form pointing you to the logout endpoint also as it is not needed anymore.
The submit button submits the form using action URL defined in <form> tag, if you want to use multiple submit buttons then you need to wrap them inside multiple forms with different values of action attribute.
However, there's no need to use multiple submit buttons for those action methods, because redundant <form> tags are inefficient. You may just use #Html.ActionLink() helper to call them like this (and then use styling for those links to look like a button):
#Html.ActionLink("Logout", "Logout", "Home", null, new { #class = "dropdown-item", #id = "btnLogout" })
If the action contains parameter(s), you should add routeValues like example below:
#Html.ActionLink("Action1", "Action1", "Home", new { str1 = "SomeValue" }, new { #class = "dropdown-item", #id = "btnAction1" })
And change HTTP method to GET because ActionLink helper generates anchor <a> tag with href attribute which should use GET method:
[HttpGet]
public ActionResult Logout()
{
// some coding
return RedirectToAction("Index", "Home");
}
The same treatment should be applied to More, Action1 and Action2 action methods as well.
Further reference:
ActionLink helper

How do i set a specific route on href with .NET Core

How do i set in the razor page, what's the route will be called on href, using tag helpers?
My Controller, named TestController:
[Route("A/B/C",Name = "Route_1")]
[Route("A/B/C/{id?}",Name = "Route_2")]
[Route("A/B/C/D/{id?}",Name = "Route_3")]
public IActionResult TestAction(string id = null)
{
...
}
The view:
<a class="btn btn-primary float-right"
style="margin-bottom:4px;"
asp-controller="TestController"
asp-action="TestAction"
asp-route-id="#Model.Id">
Click button
</a>
Use asp-route for named routes:
<a class="btn btn-primary float-right"
style="margin-bottom:4px;"
asp-route="Route_3"
asp-route-id="#Model.Id">
Click button
</a>

MVC BeginForm - passing parameters to controller using GET

I am implementing a search filter to one of my application's views. I struggle at getting routeValues passed to controller action using #Html.BeginForm() and GET request.
The action accepts the following properties:
public ActionResult Books(int id, string type, string search)
{
//rest of the code
}
The View's search box looks like this:
#model ILookup<string, CityLibrary.Models.Library.Book>
....
#using (Html.BeginForm("Books", "Collections", new { id = Model.First().First().CollectionId, type = ViewBag.BookType }, FormMethod.Get, null))
{
<div class="input-group col-md-4">
#Html.TextBox("search", null, new { #class = "form-control form-control-fixed-width", #placeholder = "Filter title..." })
<span class="input-group-btn">
<button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
}
The problem occurs when I am submitting the search box. The controller action gets the id and search string, but type is always null, even though ViewBag.BookType is not null. Fiddler shows this:
GET /Collections/Books/2?search=searchterm
Which seems to be completely ignoring type parameter in the request.
Source code in browser:
<form action="/Collections/Books/2?type=available" method="get">
<div class="input-group col-md-4">
<input class="form-control form-control-fixed-width" id="search" name="search" placeholder="Filter title..." type="text" value="" />
<span class="input-group-btn">
<button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
</form>
Does it have something to do with GET method? I would like to avoid POSTing as I would have to write another controller action with basically the same code.
EDIT: It seems that the problem occurs when I try to use GET request. POSTing the form actually passes all the parameters to the controller action. Why is that?
This behavior is in accordance with the HTML specifications, In particular for a form with method="get", (my emphasis)
Mutate action URL
Let destination be a new URL that is equal to the action except that its <query> component is replaced by query (adding a U+003F QUESTION MARK character (?) if appropriate).
So the query string value in your form's action attribute is replaced with the query string generated by the name/value pairs of the form controls.
Two options to solve this:
Remove the new { type = ViewBag.BookType } from the BeginForm() method and add a hidden input for the parameter
<input type="hidden" name="type" value="#ViewBag.BookType" />
Create a custom route definition for the method so that type is added as a route parameter, not a query string value (note this must be before the Default route)
routes.MapRoute(
name: "Books",
url: "Collections/Books/{id}/{type}",
defaults: new { controller = "Collections", action = "Books" }
);
so that your current BeginForm() code will generate
<form action="/Collections/Books/2/available" method="get">
and the form submit will result in a url of Collections/Books/2/available?search=searchterm

Send string from View to Controller using httpGet - MVC

I am new to MVC so please bear with me.
I am trying to send a string from a textbox to a controller method so I can find an object in a database. However, I do not know how to send the string successfully from the view to the controller in a HttpGet request (only in HttpPost)
The code in my view
<div>
<label>Email</label>
#Html.TextBox("email")
</div>
<div class="btn btn-success">
#Html.ActionLink("Edit RSVP", "Edit")
</div>
The ViewResult method in my controller
// Problem is the email parameter is always null
[HttpGet]
public ViewResult Edit(string email)
{
// If the email the typed is find, it will display their contents on to a RsvpForm view
return View("RsvpForm", guestRepository.Find(email));
}
Anyone know how I can send this string through, I would be grateful.
Thanks
Like this:
#using (Html.BeginForm("Edit", "ControllerName", FormMethod.Get))
{
<div>
<label>Email</label>
#Html.TextBox("email")
</div>
<div class="btn btn-success">
<input type="submit" value="Edit RSVP" />
</div>
}
Note: I can't tell from your description whether or not you are trying to do this without reloading the page. This option will post the page to the controller, so you will get a page reload.
If you want this to load without posting the page, you can look into Ajax.BeginForm. Here is a StackOverflow article with a decent primer on the AJAX form.
update
For your example, you may could do something like this if you want to use AJAX. This is all untested, but may be close to what you would need.
First you can create a partial view that represents the user data that you want to display:
RsvpForm.cshtml
#model GuestData
<div class="hdr">Name</div>
<div class="value">#Model.Name</div>
<div class="hdr">Email</div>
<div class="value">#Model.Email</div>
Then you want to make sure that your controller returns the partial view based on the email that is sent via the GET:
GuestDataController.cs
[HttpGet]
public ActionResult Edit(string email)
{
// If the email the typed is find, it will display their contents on to a RsvpForm view
return PartialView("RsvpForm", guestRepository.Find(email));
}
Then you create the AJAX form to submit the request via a GET and load the partial view without reloading the page: view.cshtml
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
#using (Ajax.BeginForm("Edit", "GuestData", null, new AjaxOptions { UpdateTargetId = "UserData", HttpMethod = "Get" }, null))
{
<div>
<label>Email</label>
#Html.TextBox("email")
</div>
<div class="btn btn-success">
<input type="submit" value="Edit RSVP" />
</div>
}
<div id="UserData"></div>
The easiest way to do it is to create a form as follow :
#using(Html.BeginForm("Edit", ControllerName, FormMethod.GET))
{
#Html.Label("Email")
#Html.TextBox("email")
<input type="submit" value="Edit RSVP"/>
}
or you can use Jquery to change the link when textbox value change (which I do not recommend):
$('input[name=email]').on('change' function()
{
var value = $(this).val();
var href = $('.btn').next('a').attr('href');
href += '?email='+value;
$('.btn').next('a').attr('href', href)
});

Handling form submit event

I have the following form:
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl, #class = "form-vertical login-form", id = "loginform" }))
<button type="submit" class="btn green pull-right">
Login <i class="m-icon-swapright m-icon-white"></i>
</button>
}
And this the javascript handling the event function
$(document).ready(function () {
$("#loginform").submit(function () {
alert('Handler for .submit() called.');
return false;
});
}
However this doesn't work at all.
the alert is never triggered
That's normal, you never assigned your form an id or a class. Look at the generated HTML in your browser to understand what I mean.
You are using a completely wrong overload of the BeginForm helper.
Try this instead:
#using (Html.BeginForm(null, null, new { returnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-vertical login-form", id = "loginform" }))
{
<button type="submit" class="btn green pull-right">
Login <i class="m-icon-swapright m-icon-white"></i>
</button>
}
Now please read about the different BeginForm overloads on MSDN and compare yours with mine.
As you can see there's a difference between the routeValues parameter and the htmlAttributes parameter.

Categories