MVC Data Model from URL to Controller - asp.net-mvc

Hi i need to pass some data from an URL to a controller in MVC. The data are in #Value = #Request.QueryString["rt"] in this code:
#using (Html.BeginForm("ResetPasswordToken", "Account")){
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "Reset Password non riuscito")
<div class="container above-footer login-form">
<div class="col-md-6" align="center" style=" margin-left:25%; margin-top:100px; margin-bottom:100px;">
<div class="editor-label">
#Html.LabelFor(m => m.ResetToken)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.ResetToken, new { #Value = #Request.QueryString["rt"] })
#Html.ValidationMessageFor(m => m.ResetToken)
</div>
And i need to retrieve this value in the AccountController when i go on the submit button associated to this view. What is the best mode to do this without see it in the page?
I know is a very simple question but i need to do only this modification for tomorrow and i am very busy. Thanks to all and sorry for the question

In the controller action that rendered this view (the GET action):
model.ResetToken = Request["rt"];
return View(model);
and then in the view simply:
#Html.TextBoxFor(m => m.ResetToken)
or if you don't want this to be shown in the form you could also use a hidden field:
#Html.HiddenFor(m => m.ResetToken)
Now when the form is submitted back to the ResetPasswordToken action you can read this value from the model:
[HttpPost]
public ActionResult ResetPasswordToken(MyViewModel model)
{
// you can use the model.ResetToken property here to read the value
}
Alternatively you could include this value as part of the url when generating the action attribute of your HTML form:
#using (Html.BeginForm("ResetPasswordToken", "Account", new { ResetToken = Request["rt"] }))
{
...
}

Related

Passing data from a View to a Controller in .NET MVC - "#model" not highlighting

The following code works as I need it to:
#using (Html.BeginForm("LOLOL", "PATIENT", null))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>PATIENT</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</fieldset>
<p>
<input type="submit" value="SUBMIT" />
</p>
}
In LOLOLController:
[HttpPost]
public IActionResult LOLOL(Patient p) {
var client = new MongoClient("mongodb://localhost:27017");
var userId = _userManager.GetUserId(HttpContext.User);
string db_name = "test" + userId;
var database = client.GetDatabase(db_name);
var collection = database.GetCollection<BsonDocument>("patients");
var filter = Builders<BsonDocument>.Filter.Eq("Name", p.Name.ToString());
var document = collection.Find(filter).First();
// I'm cutting short the rest of the code, because when I do something
// similar later, "collection.Find(filter).First()" fires an exception, I'll
// explain..
return View(p);
}
I have something equivalent to taking off the fieldset element in the HTML, leaving basically just a button in the "Html.BeginForm", but then the data is clearly not binding properly, which I know because if I just have a button and no data-entry, I click the button and then I get an error saying the data cannot be found from the database. (EDIT: I now have confirmed that this is indeed because the Patient object is not being passed to the controller quite as I expected it to, seems like a brand new Patient object was created upon calling html.beginform ... I thought that maybe the old Patient object was being passed so I did not have to enter all its data members every time we use Html.BeginForm)
In sum, I want to fill out a text box, click a button to load a new page and display the value of that textbox, but have that value also persisted in essentially a session state, so that if I call another Html.BeginForm function and go into a third view, the text from the first view will be displayed in the third view, even though I did not have to type its value in the second view. Hopefully I can repeat this process, and essentially load up the data members of a class with one view per data member.
Make sure you pass the data from the previous view to the new view from your Controller. When you pass it, include #HiddenFor for those properties from the previous view in your new view. That way the new view will keep and then pass the values to your next POST.
#Html.HiddenFor(model => model.PropertyYouPassedAndWantToKeepAndPassAgain
Edit: Here's the logic for using multiple views for one object... as requested.
Model:
public class Patient
{
string Name { get; set; }
string Address { get; set; }
string City { get; set; }
}
Page1 GET:
[HttpGet]
public ActionResult Page1()
{
Patient patient = new Patient();
return View("~/Views/Page1.cshtml", patient);
}
Page 1 View... only ask for the name.
#model mysite.Models.Patient
#using (Html.BeginForm("LOLOL", "PATIENT", null))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>PATIENT</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</fieldset>
<p>
<input type="submit" value="SUBMIT" />
</p>
}
Page1 POST... get the patient and pass it on to the next view...
[HttpPost]
public ActionResult Page1(Patient patient)
{
if (ModelState.IsValid)
{
return View("~/Views/Page2.cshtml", patient); // pass your patient to the second page view with the name
}
else
{
return View("~/Views/Page1.cshtml", patient);
}
}
Page2 GET... get the patient from the prior Page1 POST and send it off to the Page2 View.
[HttpGet]
public ActionResult Page2(Patient patient)
{
// Receive patient from Page1 post and pass it to new view... includes the name
return View("~/Views/Page2.cshtml", patient);
}
Page2 View gets the object... use a HiddenFor to keep the name which you just sent from the GET.
#model mysite.Models.Patient
#using (Html.BeginForm("LOLOL", "PATIENT", null))
{
#Html.HiddenFor(model => model.Name) #* This will keep the name on your next post *#
#Html.ValidationSummary(true)
<fieldset>
<legend>PATIENT</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Address)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Address)
#Html.ValidationMessageFor(model => model.Address)
</div>
</fieldset>
<p>
<input type="submit" value="SUBMIT" />
</p>
}
Since the HiddenFor holds the Name, it will be passed on your next post. It is there but hidden from the form itself.
[HttpPost]
public ActionResult Page2(Patient patient)
{
// Because of the HiddenFor, the Name will be passed because it was kept in the view... but hidden from the form itself.
// It's basically storing it for you to pass again
if (ModelState.IsValid)
{
// Pass object with Name and Address to next controller
return View("~/Views/Page3.cshtml", patient);
}
else
{
return View("~/Views/Page2.cshtml", patient);
}
}
Page2 POST
[HttpPost]
public ActionResult Page2(Patient patient)
{
// Because of the HiddenFor, the Name will be passed because it was kept in the view... but hidden from the form itself.
// It's basically storing it for you to pass again
if (ModelState.IsValid)
{
// Pass object with Name and Address to next controller
return View("~/Views/Page3.cshtml", patient);
}
else
{
return View("~/Views/Page2.cshtml", patient);
}
}
Page3 GET
[HttpGet]
public ActionResult Page3(Patient patient)
{
// Pass patient again... to your next view
return View("~/Views/Page3.cshtml", patient);
}
Page3 View...
#using (Html.BeginForm("LOLOL", "PATIENT", null))
{
#Html.HiddenFor(model => model.Name) #* Keep name again for your next post *#
#Html.HiddenFor(model => model.Address) #* Now we are keeping the address as well *#
#Html.ValidationSummary(true)
<fieldset>
<legend>PATIENT</legend>
<div class="editor-label">
#Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.City)
#Html.ValidationMessageFor(model => model.City)
</div>
</fieldset>
<p>
<input type="submit" value="SUBMIT" />
</p>
}
And so on and so forth... until you have your model complete and want to do something with it.

ASP.NET MVC - Determine if field has an error in Razor view

I'm working on an input form in ASP.NET MVC. My input form looks like this:
#using (Html.BeginForm("Result", "Contact", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { role="form" }))
{
<h4>What do you want to tell us?</h4>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group label-floating">
<label class="control-label" for="Subject">Subject</label>
<input class="form-control" id="Subject" name="Subject" type="text">
</div>
<div class="form-group">
<input type="submit" value="Send" class="btn btn-primary btn-raised" />
</div>
#Html.AntiForgeryToken()
}
My model behind this form looks like this:
public class ContactModel
{
[Required(ErrorMessage="Please enter the subject.")]
[Display(Name="Subject")]
public string Subject { get; set; }
}
I want to conditionally apply classes and structure based on whether or not the Model is valid. I also want to do it per field. My question is, in Razor, how do determine if the "Subject" property is valid, or if it has errors? Thanks!
While ValidationMessageFor is the standard approach for displaying validation errors, the following code does exactly what you asked for and can be useful in rare circumstances:
#if (!ViewData.ModelState.IsValidField("Subject"))
{
//not valid condition
}
As was said in comments and by #PeterB - for displaying validation messages per-input should be used Html.ValidationMessageFor method somewhere near with your input on a view. But I want to notice: you have a model but do not use it in your form. More of this, you have data annotations for client and server validation and labeling and don't use them on your view too.
Please check this approach for your view:
#model /*your.possible.namespace.*/ContactModel
...
#using (Html.BeginForm("Result", "Contact", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { role="form" }))
{
<h4>What do you want to tell us?</h4>
<div class="form-group label-floating">
#Html.LabelFor(m => m.Subject, new { #class = "control-label" })
#Html.TextBoxFor(m => m.Subject, new { #class = "form-control", #id = "Subject" })
#Html.ValidationMessageFor(m => m.Subject)
</div>
}
This snippet should display the error message that you described in ErrorMessage property of Required data annotation after posting a form. You can find useful to enable an unobtrusive validation.
You can find an article about validation in ASP.NET MVC guides.
P.S.: And don't forget to perform a server-side validation in controller (for example).
In the Controller you can use ModelState.IsValid to see if there are errors, and also ModelState["nameOfField"] to see if a specific field has errors.
In the View you can use Html.ValidationSummary() (show all errors, if any) or Html.ValidationMessageFor() (show error for specific control, if any). Examples are plenty, both on & off StackOverflow.

How to execute only one form action method in asp.net mvc view?

I have this page that contains 2 forms one exists in the layout file and the other in the view file. The first form is for newsletter subscription (an ajax form) and its location is common in the footer of the page, that's why it's in the layout and is rendered as a partial view. I have another view of the contact us page with its own form (normal form).
My issue is when I submit the contact us form, the code also goes into the action method of the subscription form and returns a model error with JsonResult causing the whole view to be rendered as text. I only want the action method of the contact us form to be executed.
Here is the subscription form in a partial view file
#model MyApp.Models.Subscriber
#using (Ajax.BeginForm("NewsletterSubscription", "Shared", null, new AjaxOptions
{
HttpMethod = "POST",
OnBegin = "OnBegin",
OnComplete = "OnComplete",
OnFailure = "OnFailure"
}, new { id = "subscribeForm" }))
{
#Html.AntiForgeryToken()
#Html.TextBoxFor(model => model.SubscriptionEmail)
#Html.ValidationMessageFor(model => model.SubscriptionEmail)
<input id="btnSubscribe" type="submit" value="Subscribe" />
}
And this is how it's rendered in the _layout.cshtml file
#{ Html.RenderAction("NewsletterSubscription", "Shared"); }
Here's the other form in contactus view file
#using (Html.BeginForm("Index", "Contact", FormMethod.Post, new { id = "contactForm" }))
{
#Html.AntiForgeryToken()
<div class="theForm">
<div class="theFormUnit">
<p>Fullname</p>
#Html.TextBoxFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="theFormUnit">
<p>Email</p>
#Html.TextBoxFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="theFormUnit">
<p>Phone</p>
#Html.TextBoxFor(model => model.Phone)
#Html.ValidationMessageFor(model => model.Phone)
</div>
<div class="theFormUnit">
<p>Message</p>
#Html.TextAreaFor(model => model.Message)
#Html.ValidationMessageFor(model => model.Message)
</div>
<input type="submit" value="Submit" />
</div>
}
When I debug the code, first the action method of the contact us is executed then the action method of the subscription and returns an error since the email was not provided.
The subscription action method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult NewsletterSubscription(Subscriber subscriber)
{
if (ModelState.IsValid)
{
}
else
{
return Json(new { success = false, message = "Failure Message" });
}
return Json(new { success = true, message = "Success Message"});
}
And contact us action method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(ContactViewModel contact)
{
if(ModelState.IsValid)
{
}
else
{
}
return View(contact);
}
I tried two solutions the first one partially solved the problem and the other solved it completely.
First solution was to add the following lines in the action method of the subscription form
if (!Request.IsAjaxRequest())
{
ModelState.Clear();
return PartialView("Partial/_NewsletterSubscription");
}
Here I am checking if the request is not an ajax request, which means it's the postback request for the contact us form, in this case I clear the model state to remove the error and return a new partial view. Although this solution solved the issue but I wasn't satisfied with it because I was not convinced with the fact that action method of the subscription form gets executed with the action method of the contact us form.
So later I thought of another simple solution, which totally solved the issue and the execution doesn't go into the action method of the subscription form when submitting the contact us form.
I simply changed the action method name from "NewsletterSubscription" to "Subscribe" so instead of
#using (Ajax.BeginForm("NewsletterSubscription", "Shared", null, new AjaxOptions
I changed it to
#using (Ajax.BeginForm("Subscribe", "Shared", null, new AjaxOptions

How to use ViewBag to pass list of data from View to controller

how can i sen a list of items from a view to a controller to save it. i believe that i can use Viewbag but i dont realy no how to use ite to pass data from view to controller.
this is what i have tried
My view
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>ProductionOrderItem</legend>
<div class="editor-label">
#Html.Label("ProducrionOrderNo");
</div>
<div class="editor-field">
#Html.TextBox("ProductionOrderNo", ViewBag.ProductionOrder as int)
</div>
<div class="editor-label">
#Html.Label("OrderName")
</div>
<div class="editor-field">
#Html.TextBox("OrderName", ViewBag.ProductionOrder as string)
</div>
<div class="editor-label">
#Html.Label("OrderDate")
</div>
<div class="editor-field">
#Html.TextBox("OrderDate", ViewBag.ProductionOrder as DateTime)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
and my controller
[HttpPost]
public ActionResult Create(FormCollection collection)
{
ProductionRegistration pr = new ProductionRegistration();
ProductionItem poi = new ProductionItem();
poi = Viewbag.ProductionOrder;
pr.SaveOrder(Conn, poi);
return RedirectToAction("Index");
}
You can't pass data from ViewBag/ViewData to the controller. It's one-way only (controller to view). The only way to get data back to the controller is to post it (post-body) or send it along in a querystring.
In fact, you should really avoid ViewBag as much as possible. It was added as a convenience and like most convenience methods, it's abused more often than not. Use a view model to both pass data to the view and accept data back from a post.
You strongly-type your view with:
#model Namespace.For.My.OrderViewModel
Then, you can use the [Foo]For methods of Razor to build your fields in a strongly-typed way:
<div class="editor-label">
#Html.LabelFor(m => m.ProductionOrderNo);
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.ProductionOrderNo)
</div>
And finally in your post action, you accept the view model as a param:
[HttpPost]
public ActionResult Create(OrderViewModel model)
{
...
}
And let MVC's modelbinder wire up the posted data for you.
No more dynamics. Everything is strongly-typed end-to-end, so if something goes wrong, you'll know it at compile-time, not run-time.

how to set default value HTML.TextBoxFor()

I have a view consisting of a form and textboxes.
How can I set a default value in each box for strings and int values?
I want the page to load up each box's value so I don't need to type values.
I'm not able to change anything in the Model.
#model MyDb.Production.ProductionMaterial
#{
ViewBag.Title = "CreateMaterial";
}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>ProductionOrderMaterial</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Position)
</div>
<div class="editor-field"> //something like
#Html.TextBoxFor(model => model.Position, Or 5 )
#Html.ValidationMessageFor(model => model.Position)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ArticleId)
</div>
<div class="editor-field"> //something like
#Html.TextBoxFor(model => model.ArticleId. Or "")
#Html.ValidationMessageFor(model => model.ArticleId)
</div>
}
Create an instance of the model in your action, assign some values to the properties of the model and pass that into the View method.
In your action have:
ProductionMaterial model = new ProductionMaterial();
model.Position = 5;
return this.View(model);
This will pass the model to the view and TextBoxFor( model => model.Position ) will display 5.
I see you already got answer, but I'll show you how you can do it another way:
In Controller
public ActionResult Index()
{
//here you must set VALUE what u want,
//for example I set current date
Viewbag.ExactlyWhatYouNeed = DateTime.Now
return View();
}
In View
#Html.TextBoxFor(model => model.CurrentDate, new { #Value = ViewBag.ExactlyWhatYouNeed})
And when you will load your View, you will get field with default value (current date in our example)
Its work on MVC 4
Hope Its will be usefull info for another people.

Resources