Tempdata In Razor - asp.net-mvc

learning MVC creating a simple date time signup form. i am trying to make two textboxes for the user. One for date and one for time.
I am going to save both values in a single dateTime field in my model.
So i need to figure out how to have a form field stored in tempdata to be accessed in the controller when posted. i can then combine the two text boxes to make a dateTime to store in my model.
I know how to get the tempdata in the controller, its just the razor syntax in the form i cant quite get.
Thanks in advance.

TempData is not fit for your purpose. You can not assign value in TempData/ViewData in a View. You can assign value in TempData/ViewData in controller only and access those value in View. For more information please refer this question: TempData moving from view to controler
I suggest you to use a ViewModel in your scenario having all properties what you need in your view. Please look into answer given by Mariusz at ASP.NET MVC - How exactly to use View Models

I think a better practice would be to have a view model containing all the information you want to pass from the form to the controller.
View Model:
public class MyViewModel
{
public string Username { get; set; }
public string Password { get; set; }
public string Date { get; set; }
public string Time { get; set; }
}
Controller:
public ActionResult Signup()
{
var m = new MyViewModel();
return View(m);
}
[HttpPost]
public ActionResult Signup(MyViewModel m)
{
var username = m.Username;
var password = m.Password;
var date = m.Date;
var time = m.Time;
// ...
}
View:
#model MvcApplication5.Controllers.MyViewModel
#* ... *#
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.Username)
#Html.PasswordFor(m => m.Password)
#Html.TextBoxFor(m => m.Date)
#Html.TextBoxFor(m => m.Time)
<input type="submit" value="Submit" />
}

Related

ASP.NET MVC Details view with many display fields but a single editable field

I have a view that shows a single item with all of its fields. But I'm getting confused trying to figure out how to allow one specific field ("Status") to be updated from this view, without necessarily going into a whole other "edit" view first.
How do I http-post to the same action (Details) but saving only the "Status" field, without saving all of the other properties which are part of the view model (for display only)? Do I need a separate view model just for the Status? New to ASP.NET MVC and getting confused.
View Model
public string FirstName { get; set; }
public string LastName { get; set; }
public string Birthdate{ get; set; }
public string Status { get; set; }
//etc.
View
<div>
#Html.DisplayFor(model => model.FirstName)
#Html.DisplayFor(model => model.LastName)
#Html.DisplayFor(model => model.Birthdate)
//etc.
</div>
<div>
#TextBoxFor(model => model.Status)
<button type="submit" value="Save Status" />
</div>
Controller
[HttpGet]
public ActionResult Details(int id)
{
var person = personRepo.GetById(id);
var vm = BuildPersonDetailsViewModel(person);
return View(vm);
}
[HttpPost]
public ActionResult Details(PersonDetailsViewModel vm)
{
var person = personRepo.GetById(vm.PersonID);
person.Status = vm.Status;
personRepo.Update(person);
}
So I solved this by ensuring that the primary key field PersonID is included in the View. I didn't think I needed it originally because it started off as a read-only Details view, and PersonID wasn't needed to be displayed. But when posting data back, I needed to add it as a hidden field, so it could be passed to the controller on HttpPost. Then it can be used to locate and update the record in the database.
Furthermore, I added another method in the repository to allow for updating of just the "Status" field, since that's the only value being updated. If I use the sample code above, my solution looks something like this:
View Model
public int PersonID { get; set; }
public string Status { get; set; }
public string FirstName { get; set; }
//etc.
View
#Html.HiddenFor(model => model.PersonID)
#Html.DisplayFor(model => model.FirstName)
//etc. (all the display fields)
#TextBoxFor(model => model.Status)
<button type="submit" value="Save Status" />
Controller
[HttpPost]
public ActionResult Details(PersonDetailsViewModel vm)
{
personRepo.UpdateStatus(vm.PersonID, vm.Status);
}
This is probably not the case but since i can't tell from the sample code, do you have the Html.BeginForm(){} block around the model that you are trying to post? Also maybe try changing the <button> tag to <input type='submit' value='save status'/> instead

Get dynamic radio buttons values

I'm doing survey system on asp.net mvc 4. How can i get all radio buttons data in Controller ?
Example
$(document).ready(function(){
var AnswerCounter = 0;
$("#answer-add").click(function(){
var answertext = $("#answer-text").val();
var answerContent = $('<p>', {
class:'external',
});
var inputAnswer = $('<input>',{
id:'answer-'+AnswerCounter,
name:'rb',
class:'answer-radio'
}).attr("type","radio").appendTo(answerContent);
var labelAnswer = $('<label>').attr('for','answer-'+AnswerCounter).text(answertext).appendTo(answerContent);
$('#answers').append(answerContent);
AnswerCounter++;
});
});
You can see in the example buttons created by jquery. so i can use model binding.
Thanks.
The HTML typically geneated for MVC3 radiobuttons look like this
<input name="FeedingTime" id="FeedingTime" type="radio" value="Morning"/>
<input name="FeedingTime" id="FeedingTime" type="radio" value="Afternoon" checked="checked"/>
and when the radio button group posts, it will bind to the variable that matches the name.
[HttpPost]
public ActionResult Index (string FeedingTime){
//feeding time here is "Afternoon"
}
so to make your code bind correctly,
set the value of the input 'value' attribute in your script, and
have a variable in the ActionResult that matches the 'name' attribute in the html input element
EDIT: This answer is no longer relevant to the question being asked.
to get the value from radio buttons you can bind to them like you would a string variable; suppose in your view you have
#Html.LabelFor(m => m.FeedingTime,"Morning")
#Html.RadioButtonFor(m => m.FeedingTime, "Morning")<br />
#Html.LabelFor(m => m.FeedingTime,"Afternoon")
#Html.RadioButtonFor(m => m.FeedingTime, "Afternoon")<br />
#Html.LabelFor(m => m.FeedingTime,"Night")
#Html.RadioButtonFor(m => m.FeedingTime, "Night")
when you post back, you would capture this in a string variable
public ActionResult(..., string FeedingTime, ...){
}
normally this variable is embedded in a viewmodel such as
public class AnimalViewModel
{
public string Name { get; set; }
public string Type { get; set; }
public string FavoriteColor { get; set; }
public string FeedingTime { get; set; }
}
so that when you post
[HttpPost]
public ActionResult Index(AnimalViewModel viewModel){
...
}
it binds the viewmodel to the data automagically.
To answer your question more directly. I dont think theres a way to detect all radiobutton inputs on a page, you can only detect the results from that are posted from the radio button. There is no indication that the string posted was once the answer to a radiobutton. So, if you want to know the values of all radiobuttons on the page, you will simply have to check the values of the strings which are posted.

ASP.NET MVC: Getting values from TextBoxFor, TextBox, DropDownList and TextArea

In ASP.Net MVC I am opening one view from another view. The first view sends two values to the second view. In the second view the user can send an email.
I am having two problems.
The first problem is that the two values that I send from the first view aren't being shown in my second view.
The second problem is that I can't get the email form to trigger my email function in the controller.
Here's a more detailed explanation.
My first view named ViewOne is using the controller ControllerOne. In ViewOne I have the following code to call the second view, ViewTwo:
#Html.ActionLink("Go to second view", "ViewTwo", "Home", new { firstval = firstval, secondval = secondval }, null)
When the ActionLink is clicked, the following function in the controller HomeController is called:
public ActionResult ViewTwo(string firstval, string secondval)
{
MyModel model = new MyModel();
model.firstval = firstval;
model.secondval = secondval;
var list = new SelectList(new[]
{
new {ID="1",Name="One"},
new{ID="2",Name="Two"},
new{ID="3",Name="Three"},
},
"ID", "Name", 1);
model.myList = list;
return View(model);
}
So in the controller HomeController I attempt to populate the model myModel with the values I get from the first view, ViewOne.
The model MyModel looks like this:
public class MyModel
{
public string firstval { get; set; }
public string secondval { get; set; }
public IEnumerable<SelectListItem> myList { get; set; }
[Required]
[DisplayName("My name")]
public string reporter { get; set; }
[Required]
[DisplayName("Description")]
public string description { get; set; }
[DisplayName("Dropdown")]
public string myDropDownListValue { get; set; }
}
The view ViewTwo looks like this:
#model myapp.Models.MyModel
#{ ViewBag.Title = "Send e-mail"; }
<hgroup class="title">
<h1>#ViewBag.Title</h1>
<h2>#ViewBag.Message</h2>
</hgroup>
#using (Html.BeginForm("sendEmail"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset>
<legend>Send e-mail</legend>
<p>First value:</p>
<p>#Html.LabelFor(m => m.firstval)</p>
<p>Second value:</p>
<p>#Html.LabelFor(m => m.secondval)</p>
<p>Reporter</p>
<p>#Html.TextBoxFor(m => m.reporter)</p>
<p>Dropdownlist</p>
<p>#Html.DropDownListFor(m => m.myDropDownListValue, Model.myList as SelectList)</p>
<p>Description:</p>
<p>#Html.TextAreaFor(m => m.description, new { #cols = 150, #rows = 5})</p>
<input type="submit" value="Send e-mail"/>
</fieldset>
}
In the controller HomeController, which is the same controller that has the ViewTwo() function that gets triggered right before the above form gets drawn, I have the following function:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult sendEmail(ContactModel model) // (string keyword, string partofspeech, string reporter, string category, string description, string acceptance)
{
// code to send email
}
So I want this function, sendEmail, to get triggered whenever I submit the form. But that doesn't happen. What happens when I click the submit button (labeled "Send e-mail") is that the view ViewTwo gets reloaded and the ActionResult ViewTwo() in the controller HomeController gets triggered. This is my second (and biggest) problem.
Also, my first problem is that
<p>#Html.LabelFor(m => m.firstval)</p>
Doesn't show the value that gets sent from the first view. It shows the string "firstval". Before the form is drawn I can see in the function ViewTwo() that the value gets correctly sent from the first view.
Any ideas?
EDIT:
Second problem solved. See my reply below.
You have a few options, normally with a postback you would submit the form with an <input type="submit" value="sendEmail" />, the values in the form would be represented in a ViewModel like:
public class EmailFormViewModel()
{
public string value1 {get; set;}
public string reporter {get; set;}
//More properties on the form
}
Your endpoint would look like this:
[HttpPost]
public ActionResult SendEmail(EmailFormViewModel model)
{
//Send the email
}
If you still want to use a hyperlink to submit the form, which natively performs a GET request, you will can catch the click with javascript, and manually send the form via Ajax.
Something like:
$('#sendEmail').click(function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
data: $('#formId').serialize(),
url: '/controllerName/sendemail'
}).done(function(response) {
//Do something on success response
});
});
Update:
You should also decorate your post action sendEmail with [ValidateAntiForgeryToken] and add a #Html.AntiForgeryToken() within the form. This will help protect against cross site forgery requests.
You can build your form, endpoint and model like this:
#using (Html.BeginForm("sendEmail"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<p>#Html.LabelFor(m => m.value1)</p>
<p>#Html.EditorFor(m => m.value1)</p>
<p>#Html.LabelFor(m => m.reporter)</p>
<p>#Html.EditorFor(m => m.reporter)</p>
<p>#Html.LabelFor(m => m.myDropDownListValue)</p>
<p>#Html.DropDownListFor(m => m.myDropDownListValue, Model.myList as SelectList)</p>
<p>#Html.LabelFor(m => m.myTextAreaValue)</p>
<p>#Html.TextAreaFor(m => m.myTextAreaValue, new { #cols = 150, #rows = 5})</p>
<input type="submit" value="Send Email"/>
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SendEmail(myModel model)
{
//Send the email
}
public class myModel
{
public IEnumerable<SelectListItem> myList { get; set; }
[DisplayName('Value 1')]
public string value1 { get; set; }
[DisplayName('Reporter')]
public string reporter { get; set; }
[DisplayName('Text Area')]
public string myTextAreaValue { get; set; }
[DisplayName('Dropdown')]
public string myDropDownListValue { get; set; }
}
As long as you are already on the same controller, it will postback to /controllername/sendemail with the form data inside the post. You should also look up attributes on your models, you can enforce descriptions and validations for example. Check here for more details, its MVC 2 but still relevant.
If you really want to be able to GET the values instead of POSTing them, change the form's action to GET and change the target to be sendEmail
Remove the ActionLink and replace it with a simple submit button
I know you said you wanted to keep the ActionLink, but this will achieve the same thing
I managed to solve my first problem. Once I specified which controller the function sendEmail is in, that code finally got triggered. Like so:
#using (Html.BeginForm("sendEmail", "Home"))
Now if I can only figure out why
<p>#Html.LabelFor(m => m.firstval)</p>
isn't working then I'm home safe.
It actually prints out the string "firstval" instead of taking the value of the string variable firstval that I set in the model. (See my first post for more detailed explanation).
EDIT:
I fixed that last problem. The very werid thing is that the above code with LabelFor doesn't work. But if I do this instead:
<p>#Model.firstval</p>
then I get the value. But it doesn't get sent back to the controller when the form is submitted. But that I solved with:
#Html.HiddenFor(m => m.firstval)
So HiddenFor works for me, LabelFor doesn't.
Case closed. I'm throwing the "solved checkmark" to the guy who gave me all that help here above. He did awesome. But the real solution is in this post. :)

Partial editor to show single property of model

I have my model as follows
public class PlaceOrder
{
public int orderCode { set; get; }
public string Order_ID { set; get; }
public int orderDetailCode { set; get; }
[Required]
public string Topic { set; get; }
//50 more fields are there
}
Using editorforModel displays all the fields in the model. I want to have a editor helper which takes the property name and only shows editor for that specific property.
I wrote a create/edit/details actions for my model and working fine. What my final goals is that I want to have edit button next to every field on the details view. As soon I click on edit it allows to update and validate the input as well
EDIT
I am using following snippet for edit link
#(Html.Awe().PopupFormActionLink()
.LinkText("Edit")
.Name("editP")
.Url(Url.Action("PropertyEdit", "PlaceOrder", new
{
PropertyName = Html.NameFor(model => model.SubjectCategoryCode),
propertyValue = Html.IdFor(model => model.SubjectCategoryCode),
ordercode = Model.orderCode
})
)
.Title("Editor for " + Html.NameFor(model => model.SubjectCategoryCode))
and I want something that I pass the field name and it dispalys the relevant fields and do the validation
You could just use an EditorFor and a form for each field:
#using Html.BeginForm("action", "controller")
{
#Html.EditorFor(m => m.ordercode)
<input type="submit" />
}
#using Html.BeginForm("action", "controller")
{
#Html.EditorFor(m => m.orderDetailCode)
<input type="submit" />
}
Of course, you would need a different action for each item and you need a way to get the other values as well, since you're only posting one value to the controller. To achieve this you could include a hidden field with the id and retrieve the other values on the server.
There's the Html.EditorFor(m => m.Property) method for this (your model should be set to PlaceOrder to use this helper, as with any statically typed helpers).
Edit: Bah, Kenneth was faster :-).

MVC Binding Data

I have a MVC Project.
I have questions in a database that I want my users to answer. I have them in the database because they need to be able to be dynamic. The user needs to submit an answer for each question. So when the view displays, it shows the question and a textbox for each question.
What would the best way to go about doing this as I do not want to hard code in the question like #Html.textBox("Question1") etc.
Question 1 [__textbox1___]
Question 2 [__textbox2___]
... etc.
I'd probably have a ViewModel that contains a collection of a custom QuestionResponder type.
IEnumerable<IQuestionResponder> Questions{get;set;}
public interface IQuestionResponder{
Guid QuestionId{get;set;}
string Question{get;set;}
string Answer{get;set;}
}
Then you can create the display items you require for your new view model.
#for(var i = 0; i <= questionList .Count; i++)
{
#Model.Questions.ToList()[i].Question
#Html.TextBoxFor(m => m.Questions.ToList()[i].Answer)
}
Alternartively you can create an EditorTemplate to avoid looping in your view:
Insdie ~/Views/Shared/EditorTemplates/ add a new view called QuestionResponder (the name of your custom class).
Inside that template you can then add:
#model MyApp.Models.QuestionResponder
<div>
#Html.DisplayFor(m => m.Question)
#Html.TextBoxFor(m => m.Answer)
</div>
While you'll then call from your original view:
#Html.EditorFor(m => m.Questions)
There's builtin way of doing that in MVC. Very simple way, by the way. There are many alternatives, take a look at this article by Phil Haack to inspect them all. One of those is with dictionaries. Quesion.Id will be key, Answer will be value
Sample:
First, create appropriate ViewModels
public class AnswerQuestionViewModel
{
public Quesion Question { get; set; }
public string Answer { get; set; }
}
public class Quesion //
{
public int Id { get; set; }
// Maybe some other properties.
}
Inside ~/Views/Shared/EditorTemplates/, create editor that will render Editor.
#model Models.AnswerQuestionViewModel
#Html.HiddenFor(model => model.Question.Id)
#Html.EditorFor(model => model.Answer)
And ~/Views/ControllerName/ActionName.cshtml
#model IEnumerable<ControllerInspectorTest.Models.AnswerQuestionViewModel>
#using (Html.BeginForm())
{
#Html.EditorForModel();
<p>
<input type="submit" value="Create" />
</p>
}
And when you create post action, parameter will be filled in
[HttpPost]
public ActionResult AnswerQuestions(IEnumerable<AnswerQuestionViewModel> quesions)
{
// questions parameter is filled in correctly
//do save job;
}
Note that question parameter can by type of IList or List too

Resources