In my RequestController I have 2 methods with the same name, Create(), 1 for GET and 1 for POST.
I want to call the GET method in a button.
It works as text like this:
#Html.ActionLink("Create New", "Create")
But in a button it calls the POST Create method:
#using (Html.BeginForm("Create", "Request"))
{
<button type="submit">New Request</button>
}
RequestController methods:
//
// GET: /Request/Create
public ActionResult Create()
{
ViewBag.ID = new SelectList(db.Expenses, "ID", "Department");
var destinations = from t in db.Typevalues
where t.Typeschema.SchemaCode == "CTY"
select t;
ViewBag.Destinations = destinations;
return View();
}
//
// POST: /Request/Create
[HttpPost]
public ActionResult Create(Request request)
{
if (ModelState.IsValid)
{
db.Requests.Add(request);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ID = new SelectList(db.Expenses, "ID", "Department", request.ID);
return View(request);
}
How do I call the GET method in the button?
In your template specify the form method:
#using (Html.BeginForm("Create", "Request", FormMethod.Get)) {
<button type="submit">New Request</button>
}
What others have said should indeed work, however, I'd encourage you to think about what you're really trying to do. Based upon your code, it seems to me using a regular link (which can easily be styled as a button) would make more sense semantically.
If it's not really a form with data that needs to be submitted, in my opinion, it doesn't belong in a form.
You should replace your submit button with a plain HTML link:
<a class="button" href="#Url.Action("Create", "Request")">New Request</a>
and add a "button" class to you styles to simulate a button.
Or if you want to keep the button:
<button type="submit" onclick="top.location.href='#Url.Action("Create", "Request")'; return false;">New Request</button>
In every HTML form you should specify form method, otherwise it defaults. In your case one form (POST) goes:
#using (Html.BeginForm("Create", "Request", FormMethod.Post))
{
<button type="submit">New Request</button>
}
And the other one (GET):
#using (Html.BeginForm("Create", "Request", FormMethod.Get))
{
<button type="submit">New Request</button>
}
Or the same what you had, which default to GET:
#using (Html.BeginForm("Create", "Request"))
{
<button type="submit">New Request</button>
}
Related
I have some problems with deletion item from database (SQLServer) using parameters for that. I want to press "Delete" reference in Index() then put name parameter in Delete() and redirect action to Index() again and show content of db. When I press "Delete" reference I show nothing but start page of Index() :(
public async Task<IActionResult> Delete(string nm)
{
IQueryable<Phone> users = db.Phones;
if (!String.IsNullOrEmpty(nm))
{
users = users.Where(p => p.Name.Contains(nm));
foreach (var item in users)
{
db.Phones.Remove(item);
}
await db.SaveChangesAsync();
}
return RedirectToAction("Index");
}
#model DataApp2.Models.Phone
#{
ViewBag.Title = "Delete";
}
<form method="get">
<div class="form-inline form-group">
<label class="control-label">Name: </label>
#Html.TextBox("nm", Model.Name, htmlAttributes: new { #class = "form-control" })
<input type="submit" value="Delete" class="btn btn-default" />
</div>
</form>
Building the input yourself and using a form is a bit overkill/overcomplicated. Instead, you can leverage the .NET MVC framework to send the request to your action
by replacing the form you posted and everything inside of it with:
#Html.ActionLink("Delete", "Delete", new { nm = Model.Name })
This will generate a link (<a> tag) with the text "Delete" (first param of the ActionLink) and send the Model.Name in a data field called nm to the Delete action in your controller (second param of the ActionLink).
I've put together a proof of concept showing that this works:
View:
#Html.ActionLink("Delete", "Delete", new { nm = "hi" })
Controller Action:
public ActionResult Delete(string nm)
{
if (!String.IsNullOrEmpty(nm))
{
ViewBag.Name = nm;
}
return RedirectToAction("Index");
}
the controller is successfully setting ViewBag.Name in this example. Note as far as the issue you're having, it makes no difference that I'm returning a ActionResult here instead of async Task<IActionResult> as you are.
I'm guessing that you're not populating Model.Name in the action that initially loads the page. Please post the code for your get action that loads the view if you'd like more information. You can test this theory by sticking:
#if (string.IsNullOrEmpty(Model.Name))
{
<h1>Name is empty!</h1>
}
else
{
<h1>Name is #Model.Name</h1>
}
in your view if you dont want to step through the code via the debugger
I am new to mvc, so am still struggling with some concepts.
I have a very simple form and controller.
Controller:
public class InquiryController : BaseController {
public ActionResult Index() {
return View();
}
public ActionResult Search(int Id) {
int newid = Id;
return View();
}
}
and the form:
#using (Html.BeginForm("Index", "Results", FormMethod.Post))
{
#Html.TextBox("id", null, new { type = "Search", autofocus = "true", style = "width: 200px" })
<input type="submit" value="Search" />
}
What is happening is that when I enter a number in the form, I want that number to be passed to the "Search" function in the controller. I do not understand how to get the form to call the controller and do its processing inside that controller. Instead, it goes to an error looking for the "results" page, which i understand comes from the BeginForm method.
So in essence, how can i get my form to pass the number entered into the search box to my controller function?
Specify what action and what controller you want to go to in the first two arguments of Html.BeginForm.
#using (Html.BeginForm("Search", "Inquiry", FormMethod.Post))
{
#Html.TextBox("id", null, new { type = "Search", autofocus = "true", placeholder = "Harvest Tag, 6 Digit Tag No.", style = "width: 200px" })
<input type="submit" value="Search" />
}
Inside the action you can access the Id like you're doing but you could also get it from FormCollection["id"] or Request["id"] as the original string and validate it to avoid getting parsing errors in case the user submits an invalid int.
The first parameter to BeginForm is the action to take, and the second is the controller to execute, so your usage should be:
#using (Html.BeginForm("Search", "Inquiry", FormMethod.Post))
The value that gets passes in is found (in this case) by the HTML ID of the input control (id)
Let's say that I have this view:
#{
ViewBag.Title = "Send Items";
}
<h2>Sent Items</h2>
<p>
#using (Html.BeginForm())
{
Html.RenderAction("AdvancedSearchEngine", "PartialViews");
}
#Html.ActionLink("Back to Selection", "MenuSelection")
</p>
I want to add an html ActionLink that will get me to another view. I want to get all the model used in the partial view in this actionlink to create the list of items that will be displayed in this view.
Something like #Html.ActionLink("See the results", "DisplayItems", new {_myObject = "blablabla"}).
Is there any way to do that?
EDIT
I have added this method:
#Html.ActionLink("See the results", "DisplayItems", "DispatchItems", new { model = Model }, null);
But once the method actually hits, the object is still null.
Create a new action in your controller:
public ActionResult DisplayItems(MyModel model)
{
// Do stuff
return View(model);
}
Then use this AcitonLink in the SendItems view:
Html.ActionLink("See the results", "DisplayItems", "ControllerName", new { model = Model }, null);
I'm not sure if I understood completely this problem but lets try.
Use AjaxHelper to do this, makes more sense, and render a partial view. The ActionLink must have some information about the model that you want to show, can be an id or anything else. Then you can render this by clicking the link and without a full page refresh. Don't forget to include JQuery reference at the main view.
#{
ViewBag.Title = "Send Items";
}
<h2>Sent Items</h2>
<p>
#using (Html.BeginForm())
{
Html.RenderAction("AdvancedSearchEngine", "PartialViews");
}
#Ajax.ActionLink("Back to Selection", "MenuSelection", new {id = Model.Id}
new AjaxOptions { HttpMethod ="GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "results")
<div id="results"></div>
public ActionResult DisplayItems(int id)
{
// Do stuff
return PartialView("");
}
Hopes this help you!
I am used to ASP.NET web forms, and am slowly learning ASP.NET MVC.
My website has a little login form on the homepage. My natural thought is that this login form may be useful in other places, and it is not the primary action of the homepage, so I want to separate it off into a partial view. And because it is related to accounts, I want the login in my AccountController not my HomepageController.
Login form is a pretty basic strongly typed partial view:
#model Models.Account.AccountLogin
<h2>Login Form</h2>
#using (Html.BeginForm("_Login", "Account")) {
#Html.ValidationSummary()
<div>
<span>Email address:</span>
#Html.TextBoxFor(x => x.EmailAddress)
</div>
<div>
<span>Password:</span>
#Html.PasswordFor(x => x.Password)
</div>
<div>
<span>Remember me?</span>
#Html.CheckBoxFor(x => x.RememberMe)
</div>
<input type="submit" value="Log In" />
}
</div>
On the homepage, I have this:
#Html.Action("_Login", "Account")
Finally, in the account controller, this:
[HttpGet]
public PartialViewResult _Login()
{
return PartialView();
}
[HttpPost]
public PartialViewResult _Login(AccountLogin loginDetails)
{
// Do something with this
return PartialView();
}
Now when I load my homepage, it looks OK and contains the form. When I click the Log In button, it takes me to myurl/Account/_Login, which contains the form, but not within the _Layout master page, just basic plain HTML and it doesn't do anything at all when I click Log In.
I am pretty sure that I have just missed some fundamental aspect of what I am supposed to be doing here, can someone please point me in the right direction?
It's because you're returning a partial view, which strips away the master page and just returns the main content. Often actions starting with an underscore are used for partials (e.g. ajaxing in a bit of a page, but not the full page). It sounds like you want a full action, and not a partial, so
[HttpPost]
public ActionResult Login(AccountLogin loginDetails)
{
// Do something with this
return View();
}
The issue here is that you are doing a fullpage postback.
You have two options, really.
Firstly, you can use a full page postback, and then call Html.Partial to display your Partial.
Something like
[HttpGet]
public ActionResult Login()
{
return View();//this typically returns the view found at Account/Index.cshtml
}
And then create a View along the lines of
#{
ViewBag.Title = "Index";
}
<h2>Title</h2>
#Html.Partial("PartialNameGoesHere")
Your partial is then rendered where indicated, but this is done when the page loads (if you look at the generated HTML, it appears exactly as though you had written it inline).
Or you can use jQuery/AJAX to load the partial on demand. Let's say you have a homepage of some description
public ActionResult Home()
{
return View();
}
public ActionResult Login()
{
return PartialView("_Login");
}
Create the view
#{
ViewBag.Title = "Index";
}
<h2>Home</h2>
<div>
<p>Hey welcome to my pretty awesome page!</p>
</div>
Show me the login!
<div id="container">
</div>
You can then load the PartialView into the container div whenever you need it, using some JS.
$(function() {
$('.my-login-link').click(function() {
$.ajax({
url: 'account/login',
success: function(data) {
$('#container').html(data);
}
});
return false;//cancel default action
});
});
In that instance, the page loads as normal without the login part. When the user clicks the link, the Login on the controller Account is called using AJAX/jQuery. This returns the HTML of the PartialView, which you can then add to the page using jQuery in the Success handler.
This question has been asked many times but I don't think the way I need it.
I'm trying to implement a login form on the home page but this form is located in a section that pops up, like you have on this site: http://myanimelist.net.
I've created a partial view for my login form:
#model ArtWebShop.Models.customers
#section Validation {
#Scripts.Render("~/bundles/jqueryval")
}
<section id="login">
#using (Html.BeginForm("LoginValidate", "Login", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
#Html.ValidationSummary()
<fieldset>
<legend>Login</legend>
#Html.LabelFor(model => model.email)
#Html.TextBoxFor(m => m.email)
#Html.LabelFor(m => m.password)
#Html.PasswordFor(m => m.password)
<input type="submit" value="Login" class="button" />
</fieldset>
}
</section>
This is shown on the home page (index.cshtml):
<section class="shown">
#Html.Partial("_LoginPartial")
#Html.ValidationSummary(true)
#Html.ValidationSummary()
</section>
The partial view is shown correctly.
But now comes the part that doesn't work.
When you press login if you haven't filled in the fields, the validation is done in my LoginController as it should but I can't seem the send the errors to my home page view when I redirect.
[HttpPost]
public ActionResult LoginValidate(string redirect)
{
if (_unitOfWork.CustomersRepository.CostumerIsValid(Request.Form["email"], Request.Form["password"]))
{
if (!String.IsNullOrEmpty(redirect) || String.Compare(redirect, "none", StringComparison.OrdinalIgnoreCase) == 0)
{
if (redirect != null) Response.Redirect(redirect, true);
}
else
{
return RedirectToAction("index", "Home");
}
}
ModelState.AddModelError("email", "You entered an incorrect email address");
ModelState.AddModelError("password", "You entered an invalid password");
return RedirectToAction("index", "Home");
}
That's my loginValidation. Since nothing is filled in the errors are added to the ModelState and then it redirects to the home page. This however doesn't shows me the errors.I'm guessing it's exactly because I redirect but how can I solve this?
You can use TempDataDictionary to store the ModelStateDictionary between redirects.
TempDataDictionary Class
Represents a set of data that persists only from one request to the next.
In your LoginValidate action you would store the ModelState like so:
public ActionResult LoginValidate(string redirect)
{
/* Your other code here (omitted for better readability) */
ModelState.AddModelError("email", "You entered an incorrect email address");
ModelState.AddModelError("password", "You entered an invalid password");
// Add the ModelState dictionary to TempData here.
TempData["ModelState"] = ModelState;
return RedirectToAction("index", "Home");
}
And in your HomeController, Index action you would check if the TempData has a ModelState:
public ActionResult Index()
{
var modelState = TempData["ModelState"] as ModelStateDictionary;
if (modelState != null)
{
ModelState.Merge(modelState);
}
return View();
}
You could make this a little bit cleaner by using custom action filters; see this blog, number 13.
You can achieve this by using jQueryUI Dialogs and AjaxForms. Please check this demo: http://demo.ricardocovo.com/EditDialogsAndFormRazor/Cars.
You can implement a similar behaviour for your login form as for the Edit functionality in the link provided. You'll find the idea explained here: http://ricardocovo.com/2012/04/06/asp-mvc3-editing-records-with-jqueryui-dialogs-and-ajaxforms-razor-version/