How can I get value from textbox "EmailList" and send it to controler? I'm always using webforms, and this is my first contact with mvc.
View:
#Html.TextBox("EmailList")
#Html.Action("SendEmails")
Controller:
public ActionResult SendEmails()
{
// some operations on EmailList
}
EDIT
And what if I need just to open simple method 'onclick'? Not actionresult. for example -
public void SendEmails()
{
// some operations on EmailList
}
So to get the value back into the controller you're going to need to issue a POST first of all so you'll want to setup your controller action for a POST:
[HttpPost]
public ActionResult SendEmails(string EmailList)
{
}
also notice I added a parameter EmailList that's named exactly the same as the control on the form. Next we need to make sure your HTML is setup right, so when you build the form control build it like this:
#Html.BeginForm("SendEmails", "{ControllerNameHere}", FormMethod.Post)
and then your text box, well leave it alone, it should work just fine.
If you want to pass the EmailList to a method then you should have a form surrounding with the email textfield
#using (Html.BeginForm("",""))
{
#Html.TextBox("EmailList")
<input type="submit" id="emailSubmit" value="Submit Email" />
}
Then write a script to override the form default behaviour
<script type="text/javascript">
$(function () {
$("form").submit(function (e) {
e.preventDefault();
var emailValue = $("#EmailList").val();
$.ajax({
url: '/Home/SendEmails',
data: { text: emailValue }
});
});
});
</script>
Now you can add a parameter to your method like this:
public void SendEmails(string text)
{
string email=text;
//or you can look into the Request.Form or Request.Querystring
}
Hope it helps
Have a model
public class EmailSubmitModel
{
public string EmailList {get; set;}
}
In your controller
public ActionResult SendEmails(EmailSubmitModel emailSubmitModel)
{
}
Related
It may be a stupid question because when I googled I can't find anybody asking this question. But my requirement is to not to show any values in the querystring. The below url shows Name and Password values in clear text, but I don't want it to show.
http://localhost:30813/Home/Index/0?Name=test&Password=test
Model:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
//public SecureString Password { get; set; }
public string Password { get; set; }
}
LoginController's view:
#using (Html.BeginForm())
{
<div>#Html.Label("Username:")</div>
<div>#Html.TextBoxFor(model => model.Name)</div>
<div>#Html.Label("Password:")</div>
<div>#Html.PasswordFor(model => model.Password)</div>
<div>
<input type="submit"
class="btn btn-primary"
value="Login"
style="line-height:normal!important;" />
</div>
}
LoginController.cs
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(User user)
{
if (IsValidUser(user.Name, user.Password))
{
return RedirectToAction("Index", "Home", user);
}
return View();
}
You are not very clear on what you want to do. You are also unclear on what you Index action method looks like. So I am going to go on what I see in front of me.
When you do this..
return RedirectToAction("Index", "Home", user);
..you are redirecting to an HTTP GET action method named Index in the Home controller. It is unclear to me if this is an empty action method or an action method that needs a User instance.
If you do not need a User instance then you can just do this:
return RedirectToAction("Index", "Home");
If you do require a User instance and you do not want to pass the values as parameters in the URL, then I suggest you do something like this (it is not my ideal way of doing it):
[HttpPost]
public ActionResult Index(User user)
{
if (IsValidUser(user.Name, user.Password))
{
TempData["user"] = user;
return RedirectToAction("Index", "Home");
}
return View();
}
And then your Home controller's Index action method will look something like this:
public ActionResult Index()
{
User user = (User)TempData["user"];
return View();
}
Now you have an instance of your user variable and can be used accordingly.
I hope this helps.
As other pointed out, when you pass some data in GET requests, that is passed using querystring. So if you don't want to show the user specific data there, you cannot keep the user object in the RedirectToAction().
One way you can achieve such functionality is to use Session variables:
In LoginController:
if (IsValidUser(user.Name, user.Password))
{
Session.Add("user",user);
return RedirectToAction("Index", "Home");
}
return View();
And in HomeController,Index():
public ActionResult Index()
{
User user = (User)Session["user"];
Session.Remove("user");
//other logics here
return View();
}
An alternative which I use for more control of my user experience is to post my form data via ajax.
Its a bit more PT but it allows me to interact with the user more in that I can easily show a progress indicator or quickly report an error message:
#using (Html.BeginForm())
{
<div>#Html.Label("Username:")</div>
<div>#Html.TextBoxFor(model => model.Name)</div>
<div>#Html.Label("Password:")</div>
<div>#Html.PasswordFor(model => model.Password)</div>
<div>
<input type="button"
class="btn btn-primary"
value="Login"
style="line-height:normal!important;" />
</div>
}
<script>
$('form button').on('click', function() {
Login();
});
function Login() {
$('#progress').show(); // indicate work is being done
var Name = $('#Name').val();
var Password = $('#Password').val();
var User = { "Name": Name, "Password": Password };
$.post('/Home/Login', User, function(data) {
if (!data.IsOk) {
$('#progress').hide(); // work complete, stop showing progress
alert(data.Message); // show an error message from the controller
}
else {
location.href = '#Url.Content("~/")';
}
});
}
</script>
This is over-simplified. You can do a lot more. As in my case, I'm displaying MDL dialogs that have the error message and titles on them.
The controller looks something like this:
[HttpPost]
public JsonResult Login(UserViewModel user)
{
try
{
if (IsValid(user))
{
generateCookie(user);
return Json(new { IsOk = true }, JsonRequestBehavior.AllowGet);
}
else
{
return Json(new { IsOk = false, Message = "Invalid user credentials" }, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
return Json(new { IsOk = false, Message = ex.Message }, JsonRequestBehavior.AllowGet);
}
}
Once again, I've over-simplified this so as to give you the gist of it. The Controller handles all of the backend logic and database querying, and the View takes care of presentation.
If the user is valid, the Controller will return a true bool value to the View which will then redirect back to the home page which is catered to show dynamic content.
On a final note, its worth mentioning that MVC comes with built-in login functionality which is probably a lot more secure that writing our own. I'm not exactly sure how to use it though and I have little time available to figure it out but its something you might want to investigate.
I am working with a screen that needs to perform a payment based on the selected "Payment Methods" exposed with a checkbox for each one as you can see in the following mockup.
The most important thing, is that every payment method has its own logic based on the API that each provide to us where some of them need to redirect a URL for login on their site (i.e. PayPal), and some others only to specify some credentials and execute the payment itself. So, according with this, we have been forced to create a controller for each one in order to delegate the interaction with the user once he chose an option. Being more clearer, it will be something like this:
public class PayPalController : BaseController, IPaymentController
{
public ActionResult Pay()
{
//logic for a pay with PayPal
return View("PaymentSuccess");
}
}
public class BankOfNigeriaController : BaseController, IPaymentController
{
public ActionResult Pay()
{
//logic for a pay with Bank Of Nigeria
return View("PaymentSuccess");
}
}
public class BankOfAngolaController : BaseController, IPaymentController
{
public ActionResult Pay()
{
//logic for a pay with Bank Of Angola
return View("PaymentSuccess");
}
}
public interface IPaymentController
{
ActionResult Pay();
}
Focused on the view that I exposed on the top, I am wondering which is the best practice to call the proper action method.
Option 1: consists on create a middle controller that redirects to the proper action.
The ViewModel has an string that it will be used for the redirect URL as selected option. In example: "PayPal" or "BankOfNigeria".
public class PayPalPaymentViewModel
{
[Required]
public string PaymentSelected { get; set; }
}
The View shows a begin form that will POST to a middle controller that, according with the chosen option will perform another redirect.
#model Bollore.IES.Web.Models.PaymentMethodViewModel
#{
ViewBag.Title = "Payment Methods";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("RedirectPay", "PaymentMethod", FormMethod.Post))
{
//HTML WITH LIST OF CHECKBOXES
<input type="submit" />
}
The MIDDLE Controller receives in the ViewModel the chosen method, and redirects to their own controller. I didn't test it, at the moment is only pseudo-code.
public class PaymentMethodController : BaseController
{
[HttpGet]
public ActionResult RedirectPay()
{
//returns the view
return View();
}
[HttpPost]
public ActionResult RedirectPay(PaymentMethodViewModel model)
{
//it could be "PayPal/Pay" or "BankOfNigeria/Pay", etc.
return RedirectToAction("Pay", model.PaymentSelected);
}
}
Option 2: consists on redirect the action directly from the client-side of the view without passing over the middle controller, which in this case, it will only exist for the GET of the view.
The View will be gotten by the PaymentMethodController, but the POST the the "payment method" action, will be done by javascript.
#model Bollore.IES.Web.Models.PaymentMethodViewModel
#{
ViewBag.Title = "Payment Methods";
Layout = "~/Views/Shared/_Layout.cshtml";
}
//LIST OF CHECKBOXES AND ALL THE STUFF
<input id="clickMe" type="button" value="Save" onclick="callPaymentMethodAction();" />
<script type="text/javascript">
function callPaymentMethodAction(e) {
var selectedMethodUrl = GetMethodSelectedUrl(); //it will return 'PayPal', 'BankOfAngola', etc
$.ajax({
url: 'selectedMethodUrl',
data: { id: id },
success: function(){
alert('Payed');
}
});
};
</script>
I repeat that is a pseudo-code that could not compile, but I hope you get the idea.
So, which of this two is the best approach to deal with a problem like
this? How can you manage the fact to be able to call multiple
controllers from the view?
Ok so I have an Html.DropDownList and I want to be able to execute a controller method ActionResult output(string test) and send a parameter to it. I have something like this already but I get an Uncaught TypeError: Cannot set property 'action' of null message:
#Html.DropDownList(
"revisions", ViewData["revisions"] as SelectList,
new
{
onchange = "this.form.action = '/Shops/output('test')'; this.form.submit();"
})
How do I go about fixing my code?
If your Action method's parameter name is id,
public ActionResult output(string id)
{
//do something
}
then you may use your form action url like this.(The default routing will take care of rest)
/Shops/output/somestringhere.
If you have a different name, use that as the query string
public ActionResult output(string name)
{
//do something
}
Now use your form action url like
/Shops/output?name=somestringhere
Another suggestion about your code is to avoid Viewdata for rendering the dropdown. Try to use strongly typed view model and it's properties for transfering data to your view. Also try to move your javascript from your view and make it unobutrusive. So that your view stays as clean markup only.
Assuming you want to show a Revision dropdown in a document create view, Add a property to your viewmodel to have the dropdown items.
public class DocumentCreateViewModel
{
//Other properties also here
public List<SelectListItem> Revisions{ set;get;}
public int SelectedRevision { set;get;}
public DocumentCreateViewModel()
{
Revisions=new List<SelectListItem>();
}
}
and in your GET action, fill the dropdown content to the Revisions property.
public ActionResult Create()
{
var vm=new DocumentCreateViewModel();
vm.Revisions=GetRevisionItemsFromSomeWhere();
return View(vm);
}
And in your strongly typed view,
#model DocumentCreateViewModel
#using(Html.Beginform())
{
#Html.DropDownListFor(x => x.SelectedRevision,
new SelectList(Model.Revisions,"Value","Text"), "Select..")
<input type="submit" />
}
Now to handle the form submit on change event of dropdown, add this script.
$(function(){
$("#SelectedRevision").change(function(){
var _this=$(this);
var selectedRevision=_this.val();
$("form#YourFormIDHere")
.attr("action","./Shops/output/"+selectedRevision).submit();
});
});
Instead of hardcoding the url to shops/output, you may use the razor helper method(#Url.Action) to get the proper path.
#Html.DropDownList(
"revisions", ViewData["revisions"] as SelectList,
new
{
onchange = "submitForm();"
})
and your Javacript goes here
function submitForm()
{
var form = document.forms[0];
form = '/Shops/output?test=test';
form.submit();
}
Below Scenario, I think I must see the START text in my form when first loaded.
When I click send data button and submit, I was waiting to see FINISH text in my form.
Buy the START text never changes when I click the button and post the form...
Anybody can tell the problem?
MY CONTROLLER:
namespace MvcApplication1.Controllers
{
public class BuyController : Controller
{
public ActionResult Index(BuyModel model)
{
if (Request.HttpMethod == "GET")
{
model.Message= "START";
return View(model);
}
else
{
BuyModel newModel = new BuyModel();
newModel.Message= "FINISH";
return View(newModel);
}
}
}
}
MY VIEW :
#model MvcApplication1.Models.BuyModel
#using (Html.BeginForm("Index", "Buy", FormMethod.Post))
{
#Html.TextBoxFor(s => s.Message)
<button type="submit" >Send</button>
}
MY MODEL:
public class BuyModel
{
public string Message { get; set; }
}
public class BuyController : Controller
{
public ActionResult Index()
{
BuyModel model = new BuyModel();
model.Message= "START";
return View(model);
}
[HttpPost]
public ActionResult Index(BuyModel model)
{
model = new BuyModel();
model.Message= "FINISH";
ModelState.Clear(); // the fix
return View(model);
}
}
View:
#model MvcApplication1.Models.BuyModel
#using (Html.BeginForm("Index", "Buy"))
{
#Html.TextBoxFor(s => s.Message)
<button type="submit" >Send</button>
}
Your issue is because your original code, that Action Method will only be executed as an HTTP GET request. ASP.NET MVC allows you to specify a post with the [HttpPost] attribute (see above code).
I'm not sure what you are getting at with your POST desired-behavior. It seems like you are just wiping out whatever form values are pushed on the POST. So modify my above code accordingly, but it should give you the general idea.
Edit: it seems to be that the text box is retaining its value after the POST. It's not just with "START", but if you type anything into that text box and hit submit, you'll have a POST with the exact same text in the text box that was there when you submitted the form.
Edit Edit: see the changed code. Call ModelState.Clear() in your POST action method and you'll have the right value reflected.
If you are posting, and not returning a RedirectResult, by default the helpers will use the value from ModelState. You either need to clear ModelState or have a different approach.
The PRG (post redirect get) pattern in MVC is very important. So if its a post, and you aren't redirecting, the helpers assume there is an error that needs to be corrected and the value is pulled from ModelState.
I have a weird need in an ASP.NET MVC 3 application which blocks my current progress. Here is the case:
I have a little search engine for the products and I render this search engine on multiple pages. This SE makes a HTTP POST request to product controller's search action. It fine till here.
Let's assume that I am on home controller's index action (/home/index). I make a search and check if ModelState.IsValid. As a result, it is not valid. So, I should return this back with the entered model (so that user won't lose the values) and model state errors. But when I do that I ended up with different URL (/product/search) as expected.
If I do a redirect, I lose the ModelState and cannot display error messages.
I have different solutions so far and they all look dirty. Any idea?
Edit
Here is a little project which demonstrates this:
This is the ProductController:
public class ProductController : Controller {
[HttpPost]
public ActionResult Search(SearchModel searchModel) {
if (ModelState.IsValid) {
//Do some stuff...
return RedirectToAction("Index", "SearchResult");
}
return View(searchModel);
}
}
This is the SearchModel:
public class SearchModel {
[Required]
public string ProductCategory { get; set; }
[Required]
public string ProductName { get; set; }
}
This is the *_SearchPartial*:
#model MvcApplication20.SearchModel
#using (Html.BeginForm("search", "product"))
{
#Html.EditorForModel()
<input type="submit" value="Search" />
}
And finally this is the Home controller Index action view which renders the *_SearchPartial*:
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
#Html.Partial("_SearchPartialView")
Here, when I submit the form and if the model state fails, how should I proceed at the Product controller Search action?
Here, when I submit the form and if the model state fails, how should
I proceed at the Product controller Search action?
Normally in this case you should render the _SearchPartialView but not as a partial but as a full view with layout so that the user can fix his errors. No need to stay at Home/Index in this case:
[HttpPost]
public ActionResult Search(SearchModel searchModel) {
if (ModelState.IsValid) {
//Do some stuff...
return RedirectToAction("Index", "SearchResult");
}
// since we are returning a view instead of a partial view,
// the _SearchPartialView template should be displayed with the layout
return View("_SearchPartialView", searchModel);
}
And if you wanted to stay on the same page upon error you could use an AJAX call to perform the search. So you would AJAXify this search form and then in the success callback test the result of the Search action and based on it decide whether to refresh the partial in order to show the error or redirect to the results action using window.location.href:
something along the lines of:
$(document).on('submit', '#searchForm', function() {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function(result) {
if (result.redirectTo) {
// no validation errors we can redirect now:
window.location.href = result.redirectTo;
} else {
// there were validation errors, refresh the partial to show them
$('#searchContainer').html(result);
// if you want to enable client side validation
// with jquery unobtrusive validate for this search form
// don't forget to call the .parse method here
// since we are updating the DOM dynamically and we
// need to reattach client side validators to the new elements:
// $.validator.unobtrusive.parse(result);
}
}
});
return false;
});
This obviously assumes that you have now wrapped the partial call in a div with id="searchContainer" and that you provided an id="searchForm" when generating the search form:
<div id="searchContainer">
#Html.Partial("_SearchPartialView")
</div>
and now the search action:
[HttpPost]
public ActionResult Search(SearchModel searchModel) {
if (ModelState.IsValid) {
//Do some stuff...
return Json(new { redirectTo = Url.Action("Index", "SearchResult") });
}
return PartialView("_SearchPartialView", searchModel);
}
As far as I know the ModelState is lost when doing a RedirectToAction, the solution would be to save the modelstate in the TempData one example of this, that I'm using is this:
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#prg
This is also discussed in various posts for instance MVC Transfer Data Between Views