where does value get stored after onchange in MVC? - asp.net-mvc-4

I want to do a drop down list and when I click the submit button, it posts back the selected value.
I don't know if I'm doing it right but I've searched around and came up with this so far.
I just want to know if I'm doing it right and where it would store the value once it posts back.
#using (Html.BeginForm())
{
#Html.DisplayName("Name:")<br />
#Html.TextBox("NAME")<br />
#Html.DisplayName("Password:")<br />
#Html.TextBox("PASS")<br />
#Html.DisplayName("Team Name:")<br />
#Html.DropDownListFor(x => x.Teams, new SelectList(Model.Teams, "value", "TeamNAME"), new {onchange = "submit()"})
<input type="submit" value="ADD" />
}
Want to get the value here
[HttpPost]
public ActionResult Index()
{
//GET VALUE OF THE SELECTED TEAM HERE
return RedirectToAction("Index");
}

It looks pretty close -- the only thing is that, you should be consistent in using the model-bound HTML helper methods, or not. That is, use TextBoxFor and DropDownListFor, or TextBox and DropDownList, but don't mix and match.
If you use the model-bound ones, then you should be able to simply add the model type as a parameter to your postback action:
public ActionResult Index(MyModel postback)
For the unbound ones, you can add parameters individually using their names:
public ActionResult Index(string NAME, string PASS, string TEAM)
(assuming you'd change to #Html.DropDownList("TEAM", new SelectList(Model.Teams, "value", "TeamNAME"), new {onchange = "submit()"}))

Details: The below is assuming you are using a Model called Team and that you are using that Model in the View. (code not tested)
View
#Html.DropDownListFor("Teams", String.Empty)
Controller
[HttpGet]
public ActionResult Index()
{
ViewBag.Teams = new SelectList(db.Team, "TeamId", "TeamNAME");
return View();
}
[HttpPost]
public ActionResult Index(Team team)
{
// Here is your selected Team id
//team.TeamId
return View();
}
Check out this Tutorial for more info on using the DropDownList
MVC 4 Tutorial

Related

What is difference between Page() and Rediirect() to self in ASP.NET Core Razor pages?

I have a very simple page that has 2 forms. When I submit one form it resets the other. There is some kind of hidden optimization is going on because when I refresh the page it presents the correct result.
Here is the page:
<div asp-validation-summary="All"></div>
<div class="col-md-3">
<form method="POST">
<fieldset>
<div>Host Name: <input asp-for="ClientConfig.HostName" /></div>
<div>Responses in HTML? <input type="checkbox" asp-for="ClientConfig.Html" /></div>
<input type="submit" asp-page-handler="ClientConfiguration" />
</fieldset>
</form>
<p>Base URL = #Model.ClientConfig.Summary</p>
</div>
<form method="POST">
<fieldset>
<div>Name: <input asp-for="Customer.Name" /></div>
<div>New? <input type="checkbox" asp-for="Customer.New" /></div>
<input type="submit" asp-page-handler="Customer" />
</fieldset>
</form>
<ul>
<li>Customer = #Model.Customer.Summary</li>
</ul>
Here is the model...
public class ClientConfig
{
public static ClientConfig Instance { get; set; } = new ClientConfig();
[Required, StringLength(100)] public string HostName { get; set; } = "LocalHost";
public bool Html { get; set; }
public string Summary => HostName + (Html ? " (Html)" : "");
}
public class Customer
{
public static Customer Instance { get; set; } = new Customer();
[Required, StringLength(100)] public string Name { get; set; } = "Default";
public bool New { get; set; }
public string Summary => Name + (New ? " (New)" : "");
}
public class IndexModel : PageModel
{
public IndexModel()
{
ClientConfig = ClientConfig.Instance;
Customer = Customer.Instance;
}
[BindProperty] public ClientConfig ClientConfig { get; set; }
[BindProperty] public Customer Customer { get; set; }
public async Task<IActionResult> OnPostCustomerAsync()
{
Customer.Instance = Customer;
return Page();
}
public async Task<IActionResult> OnPostClientConfigurationAsync()
{
ClientConfig.Instance = ClientConfig;
return Page();
}
}
So what is "return Page();" doing? According to the documentation it is simply rendering the current page. Not true. To verify this, simply refresh the page. It will be different, accurate with both forms filled in. Also if you replace "return Page()" with "return Redirect("/Index");" the result will also be accurate. So again, what is "return Page()" doing? There is some kind of undocumented optimization that resets all the forms except the one recently submitted.
You have multiple separate forms on your page with separate form values: In one form you are submitting the client configuration object, in the other you are submitting the customer object.
So when you are actually submitting a form, only that form's data is being submitted. For example, if you are submitting the customer form, the client configuration data is not being transferred in the POST request (and the other way around).
As such, when you render the page by returning Page(), only the data that is currently in the page model is being rendered. If you are submitting the customer form, then only the customer data is available (same for the client configuration form).
This happens simply because you only have partial data on a page where you would need more to fill in all forms. If you want to prevent that, you will have to combine the data into a single model and form.
Now, if you refresh the page in the browser, then your browser is typically smart enough not to clear form values immediately. If you do a hard refresh using Ctrl + F5, then the browser should also reset the values.
It's also possible that your browser is performing an auto-fill for the forms here. This will typically only apply for GET requests. So that could be the reason why you are getting this result when you return a Redirect() because that completes the form POST with a GET request.
When I submit one form it resets the other.
That's the expected behavior for the way you coded your page. When the form POSTs to the server, the server does three things:
creates a new IndexModel object using its constructor,
binds the object's properties to the POSTed form values, and
binds the object to its view.
In your code, step (1) resets properties to their default values. Step (2) overwrites those defaults with POSTed form values. Since you're submitting only one form, the other form's values retain their defaults. That's why submitting one resets the other.
So what is "return Page();" doing? According to the documentation it is simply rendering the current page. Not true. To verify this, simply refresh the page. It will be different, accurate with both forms filled in. Also if you replace "return Page()" with "return Redirect("/Index");" the result will also be accurate.
When you submit a form, return Page() renders the page in the context of a POST. On the other hand, when you refresh or redirect, the context is a GET. The difference you see happens because the context is different: the response to a POST is different from the response to a GET.
Right. After quite a long time of pondering this problem, I've finally figured it out. The problem: Razor pages moves in mysterious ways its wonders to perform.
My initial assumption was wrong. The page model constructor is not being bypassed. The page model is being properly constructed from static values. However after construction all bound objects on the page are reset. So this is not an "undocumented optimization"...it is an undocumented impairment.
The fix for this is to reset the page model from static values before returning Page().
public async Task<IActionResult> OnPostCustomerAsync()
{
Customer.Instance = Customer;
ClientConfig = ClientConfig.Instance;
return Page();
}
public async Task<IActionResult> OnPostClientConfigurationAsync()
{
ClientConfig.Instance = ClientConfig;
Customer = Customer.Instance;
return Page();
}
This is obviously a massive kluge, but no elegant solution exists. Anyone?

asp.net mvc add parameter with each action view

I have a site which have many action like article, blog, news, stories, myths, books, audio, video.
Now I want if i pass a query string in index action like
wwww.mysite.com/english
then every action must be have this parameter automatically like
wwww.mysite.com/article/englishwwww.mysite.com/blog/englishwwww.mysite.com/news/englishwwww.mysite.com/stories/englishwwww.mysite.com/myths/englishwwww.mysite.com/books/englishwwww.mysite.com/audio/englishwwww.mysite.com/video/english
Please help me and suggest a good way
Store the passed passed parameter in a session variable and then access on each action. Example:
public ActionResult Index(string lang)
{
Session["Language"]= lang;
return View();
}
And then fetch in other actions like:
public ActionResult News()
{
string lang= Session["Language"].ToString();
// Do something with the lang...
return View();
}

The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[X]', but this dictionary requires a model item of type 'X'

*CORRECTION
The problem occurs when my view is called to populate a list from my user table.
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Mike.Models.User]', but this dictionary requires a model item of type 'Mike.Models.User'.
Here is my controller action:
public ActionResult Registration(Mike.Models.User user)
{
if (ModelState.IsValid)
{
using (var db = new UserContext())
{
var crypto = new SimpleCrypto.PBKDF2();
var encrypPass = crypto.Compute(user.password);
var sysUser = db.Users.Create();
sysUser.LastName = user.LastName;
sysUser.FirstName = user.FirstName;
sysUser.Email = user.Email;
sysUser.password = encrypPass;
sysUser.passwordSalt = crypto.Salt;
sysUser.UserID = user.UserID;
db.Users.Add(sysUser);
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
}
return View(user);
}
Can someone please help me.... There are responses to similar questions on the internet but I believe mine is unique.. I have searched for weeks to no avail.
Thanks in advance,
Renior
Here is my simple controller action...
public ActionResult Index()
{
return View(db.Users.ToList());
}
and my razor syntax.
#model IEnumerable
Im trying to populate a view of my user table list..
In your Registration view at the top where your model declaration is, instead of this:
#model List<Mike.Models.User>
you need to have:
#model Mike.Models.User
You probably used strongly typed scaffolding feature to generate your view but instead of details option you chose a list option...
Take this at face value - yours is not unique. Your problem is you are passing an array of user to a controller action that expects a user.
You need to post your HTML but it is probably something like #model List user or something instead of a single user.
If your model represents a single user then pass that to the controller. If opposite, do opposite,
If you want to pass a list to the controller use list users
edit
make your razor syntax
#model Mike.Models.User

How to apply CSS to Html.ValidationSummary at runtime

I am building my first MVC4 website and I would like to show success message when page successfully submitted. I have achieved by using ModelState.AddModelError(("", "Data successfully saved."); but it is showing in the red color. I want to apply different css at runtime based on some conditions.
Thanks.
I recommend using TempData instead of changing validationsummary and #von described it very well. Use bootstrap. You could do something like this:
Controller
[HttpPost]
public ActionResult ManageUsers(UserViewModel model)
{
if (ModelState.IsValid)
{
User obj = new User();
obj.UserName = model.Email;
obj.FirstName = model.FirstName;
obj.LastName = model.LastName;
obj.Email = model.Email;
obj.Phone = model.Phone;
obj.Notes = model.Notes;
obj.Authorized = model.Authorized;
UserRepository.SaveUser(obj);
TempData["Success"] = "Yes";
}
return View(model);
}
View
#Html.ValidationSummary()
#if (TempData["Success"] != null)
{
<div class="alert alert-success">
×
<strong>Success!</strong> The User account was created.
</div>
}
Normally when the result of an action method is successful a redirect happens, maybe that's what you want, especially if your result is not a json result. But if you are returning the same view after your post then you are doing it incorrectly. If the ModelState is valid on a post, that is if the validation passed (e.g. required fields are supplied), and you add an error message by doing ModelState.AddModelError(("", "Data successfully saved.") then you are making the ModelState go into an invalid state. That is the reason why you have the red color.
Now assuming you really want to return the same view then I suppose you have something like:
[HttpPost]
public ActionResult YourActionMethod(YourModel model)
{
// some code goes here
ModelState.AddModelError(("", "Data successfully saved.")
return View(", model);
}
What you should have instead is something like this:
[HttpPost]
public ActionResult YourActionMethod(YourModel model)
{
// some code goes here
ViewBag.SuccessMessage = "Data successfully saved.";
return View(", model);
}
Then on your view something like:
#Html.ValidationSummary(true)
if (!string.IsNullOrWhiteSpace(ViewBag.SuccessMessage)) {
<div class="success-summary">
<p>#ViewBag.SuccessMessage</p>
</div>
}
Note that you don't need an additional # before the if, that code assumes it's inside a form tag, using #using. And then for the css:
.success-summary {
color: #3366FF;
}
You can actually use either ViewData or ViewBag. To know more about the difference of the two you can visit this SO page.
UPDATE:
[HttpPost]
public ActionResult YourActionMethod(YourModel model)
{
//
If (ModelState.IsValid) {
#ViewBag.IsModelValid = true;
ModelState.AddModelError("", "Data successfully saved.");
return View(model);
}
ViewBag.SuccessMessage = "Data successfully saved.";
return View(", model);
}
Your view:
#Html.ValidationSummary(false, "", new { #class= (ViewBag.IsModelValid!=null && ViewBag.IsModelValid) ? "success-summary" : "" })
Von, I too appreciate your answer, but I agree with MaxPayne that you didn't quite provide an answer for the question, more of a work around IMO.
I too am looking at a way to style the ValidationSummary without the extra baggage of using the ViewBag.
I do agree that you shouldn't return to the same view after a post unless there are errors, but I do believe there are times when one might want to change the ValidationSummary style dynamically without having to use the ViewBag.
So far this is my only lead http://westcountrydeveloper.wordpress.com/2011/07/06/mvc-validation-part-4-styling-the-validation-controls/
I suppose you could use some JQuery to change the element's css attributes based on the Validation response.
var valid = $("#formID").validate().element("#ElementID");
//or
var valid = $('#formID').validate();
// Then use $(".ElementClass").css({}); to change the the style

Persisting MVC4 controller data thru multiple post backs

I have a MVC4 controller that calls its view multiple times, each time with a different set of ViewBags. The view renders the contents of a Form based on the absence or presence of those ViewBags via something like this:
#using (Html.BeginForm())
{
#if (ViewBag.Foo1 != null)
{
#Html.DropDownList("Bar1",....
}
#if (ViewBag.Foo2 != null)
{
#Html.DropDownList("Bar2",....
}
<input name="ActionButton" type="submit" value="Ok"" />
}
Each time the user clicks the submit button, the controller checks to see what is in the collection and makes a new set of ViewBags before calling the view again, sort of like this:
public ActionResult Create()
{
ViewBag.Foo1 = "blawblaw";
return View();
}
[HttpPost]
public ActionResult Create(FormCollection collection)
{
if (collection["Bar1"] != null)
{
string FirstPass = collection["Bar1"];
ViewBag.Foo2 = "blawblaw";
}
if (collection["Bar2"] != null)
{
string SecondPass = collection["Bar2"];
ViewBag.Foo3 = "blawblaw";
}
return View();
}
What I need to do now is somehow have each pass thu the controller 'remember' something about its previous passes. That is, in my example, the second pass thru the controller (the one where collection["Bar2"] is true), the value of FirstPass is null.
How can I do that?
In that case have a look at best practices for implementing a wizard in MVC. Some good suggestions here. Personally I would still consider using separate and distinct urls. Also, If you have db access in your solution you can still store temporary data before updating the main model. Think about what you want to happen if the user doesn't complete the whole journey the first time round...