How do I retrieve the value of a textbox in asp.net mvc to store the value on to some variable?
I have a textbox like this <%=Html.TextBox("testbox") %> on the index view page.
I have a button like this <input type="submit" />
I'm using the default view page which comes when you open a new mvc app.
Thanks.
In your controller;
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Search(FormCollection collection)
{
String g = collection["textFieldname"]
}
or you could use;
TryUpdateModel(modelName);
The above is the prefered solution. If you need more info on TryUpdateModel then post a comment and I'll flesh it out for you.
EDIT:
Rather than explain it let me simply show you;
In your controller:
public class MyFormViewModel
{
public string myInput {get; set;}
}
public ActionResult Search()
{
MyFormViewModel fvm = new MyFormViewModel();
return View(fvm);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Search(FormCollection collection)
{
MyFormViewModel fvm = new MyFormViewModel();
TryUpdateModel<MyFormViewModel>(fvm);
string userInput = fvm.myInput;
}
Then in your view;
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<YOURNAMESPACE.Controllers.MyFormViewModel>" %>
<%= Html.TextBox("myInput", Model.myInput) %>
Notice two things.
The page is inheriting from your model/class defined in the controller. Not the best place for it but as an example it'll do.
The other thing is that the text box is name the same as the property in the model. In this case myInput.
When the controller does UpdateModel it'll reflection the thing out and match up the textbox name with the name of the field within your form view model.
Make sense?
EDIT 2
Also don't forget to wrap the button and your field in a;
<% using (Html.BeginForm()) {%>
Related
I am a real beginner at ASP.NET and working with MVC2 + EF4 in Visual Studio 2010.
I am trying to use the MVVM pattern and strongly typing my View to a ViewModel.
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="True" CodeBehind="~/Views/Options/Index.aspx.cs" Inherits="System.Web.Mvc.ViewPage<OptionsViewModel>" %>
My OptionsViewModel looks like this:
public class OptionsViewModel
{
public List<DeskPreference> DeskPreferences { get; set; }
public List<DayPreference> DayPreferences { get; set; }
}
In the controller I create a new OptionsViewModel and do return View(myOptionsViewModel);
Then, for example, I want to check/uncheck some boxes based on what is in DayPreference. I don't get how to access the model from my code behind file, which looks like this:
using System.Web.Mvc;
using DeskRota_v1.ViewModels;
public class OptionsPage : System.Web.Mvc.ViewPage<OptionsViewModel>
{
protected void Page_Load(object sender, EventArgs e)
{
setCheckBoxes();
}
private void setCheckBoxes()
{
foreach (DayPreference dayPreference in Model.DayPreferences)
{
\\ check boxes here
}
}
It comes up with "The name 'Model' does not exist in the current context". Also if I try to do <% Model. %> in the view there is no intellisense, which I thought there should be. Could somebody please explain what I am doing wrong? How am I supposed to access the ViewModel and its properties?
Your controller will have two overloads of each action method for each view that you need to post back: one with an HttpGet signature and one with an HttpPost signature. The GET version will be called on the first load of the page and will set the initial page values.
The POST version will be called on form submit and accept your viewmodel as an arg. MVC will automagically reconstruct it with the values that were posted in your form (assuming you're using relatively simple types. More complex types is doable but more complicated).
My own convention is to have a work unit in the ViewModel that is responsible for persisting or otherwise processing the values that were submitted. Do NOT put this sort of thing in the controller.
Your viewmodel will need a parameterless constructor, which is the version MVC will use when reconstituting it on page submit. In general I also have a second constructor I use on the GET version so that the VM can instantiate it's initial values.
[HttpGet]
public ActionResult Index(int somethingICareAbout)
{
return View(new IndexViewModel(somethingICareAbout));
}
[HttpPost]
public ActionResult Index(IndexViewModel viewModel)
{
viewModel.SaveChanges()/DoWork()/Whatever();
return View(new viewModel());
}
My controller returns a string which is a url of an image of an external site.
How do I display that url on the view.
I appreciate your help.
AngryHacker is correct. I am just expanding AngryHacker's answer with some code example.
Add a property in your ViewModel for the image url and return it in the first get call. Then use it in the View. Thus you are avoiding an unnecessary http request to to the action again
public class UserProfileViewModel
{
public string DisplayName { set;get;}
public string GravatarURL { set;get;}
}
and in your ACtionMethod,
public ActionResult Get(int id)
{
UserProfileViewModel objVm=new UserProfileViewModel();
objVM.GravatarURL="http://www.externalsite.com/image/tiyra.jog";
//Set other properties also.
return View(objVm);
}
and in the View which is strongly typed to your UserProfileViewModel,
#model UserProfileViewModel
<h2>"#Model.DisplayName </h2>
<img src="#Model.GravatarURL" />
<p>The image is loaded from #Model.GravatarURL</p>
Make the URL part of your model and just reference it in the View.
Perhaps you're missing the part where you have to HTML-encode your output with the <%: %> tag, a la:
<%: Html.Label(ViewData["PicUrl"].ToString()) %>
...or, if it's a string property on your model...
<label><%: Model.PicUrl %></label>
I was having a weird issue with a very simple model. When posted back to the controller, the model was always null. Not being able to find the issue, I pulled it apart rebuilt the model, adding an accessor at a time.
I finally discovered that having a string accessor called "State" and using it in a view was causing the issue:
<%= Html.HiddenFor(m => m.State) %>
Why would this happen?
Here is the model:
public class StudentSelectState
{
public string State { get; set; }
public int SelectedYear { get; set; }
public IDictionary<string, string> Years { get; set; }
}
Here is the controller:
[HttpGet]
public ActionResult SelectStudent()
{
var StudentYears = absenceServices.GetStudentYears();
var state = new StudentSelectState {Years = Lists.StudentYearListToDictionary(StudentYears)};
return View(state);
}
[HttpPost]
public ActionResult SelectStudent(StudentSelectState state)
{
var StudentYears = absenceServices.GetStudentYears();
state.Years = Lists.StudentYearListToDictionary(StudentYears);
return View(state);
}
and here is the view:
<% using (Html.BeginForm())
{%>
<%= Html.ValidationSummary() %>
<%= Html.TextBoxFor(m => m.State) %>
<%= Html.RadioButtonListFor(m => m.SelectedYear, Model.Years, "StudentYears") %>
<div style="clear: both;">
<input value="submit" />
</div>
<% } %>
The RadioButtonListFor is a HtmlHelper I wrote to populate RadioButtonLists.
I am using Ninject 2.0 to inject services into the contructor, but I don't think this has a bearing on this issue.
I could rename the accessor, but I'm curious as to why this is happening.
You could also rename the argument of your POST action.
[HttpPost]
public ActionResult SelectStudent(StudentSelectState model)
When you POST the form the following is sent in the request:
State=abcd
Now the default model binder sees that your action argument is called state and it tries to bind the abcd value to it which obviously fails because the state variable is not a string. So be careful when naming your view model properties.
To avoid those kind of conflicts I prefer to name my action arguments model or viewModel.
Yet another possibility if you don't want to rename anything is to use the [BindPrefix] attribute, like so:
[HttpPost]
public ActionResult SelectStudent([Bind(Prefix="")]StudentSelectState state)
When StudentSelectState is posted back to the controller the default mode binder (because you are not using a IModelBinder) can not know when to put in the StudentSelectState instance.
The view will not hold the state for the State property and it has to be specified in the form or obtained from a different method to be returned to the controller action.
You could use a hidden field for this or bind it using a custom IModelBinder class.
Hope this helps.
I have UserControl as well as Model for particular view. Usercontrol is working properly at the same time i try to include radiobutton on the same view with model. I am getting the Error:"The model item passed into the dictionary is of type 'System.Data.DataTable', but this dictionary requires a model item of type "MyModelName"".
So can you please help anyone.
thanks,
Mohan
The Exception Message is very descriptive and says it all. your view accepts a different model and you are passing different model to this view in controller.
Look at two places
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<AcceptedModel>" %>
and in your controller you would have something like
public ActionResult action()
{
SentModel model = new SentModel();
return View(SentModel); //i believe typeof(SentModel) != typeof(AcceptedModel) that is what is causing problem
}
Edit you can use viewModel that can contain all values required by the view
public class MYViewModel
{
System.Data.DataTable MyTable{get;set;}
Registration Myregistration{get;set;}
}
now in controller you can populate your viewModel like
public ActionResult MyActionResult(int id)
{
MyViewModel mdl = new MyViewModel();
mdl.Myregistration = new Registration();
mdl.MyTable = //code to populate table
return View(mdl);
}
and in the view you should update it to accept MyViewModel type
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MyViewModel>" %>
and then you can access them in view using
<%foreach( var row in Model.MyTable){}%>
and <%:Model.MyRegistration.FirstName%>
The Add view and the Edit view are often incredibly similar that it is unwarranted to write 2 views. As the app evolves you would be making the same changes to both.
However, there are usually subtle differences. For instance, a field might be read-only once it's been added, and if that field is a DropDownList you no longer need that List in the ViewData.
So, should I create a view data class which contains all the information for both views, where, depending on the operation you're performing, certain properties will be null?
Should I include the operation in the view data as an enum?
Should I surround all the subtle differences with <% if( ViewData.Model.Op == Ops.Editing ) { %> ?
Or is there a better way?
It's pretty easy really. Let's assume you're editing a blog post.
Here's your 2 actions for new/edit:
public class BlogController : Controller
{
public ActionResult New()
{
var post = new Post();
return View("Edit", post);
}
public ActionResult Edit(int id)
{
var post = _repository.Get(id);
return View(post);
}
....
}
And here's the view:
<% using(Html.Form("save")) { %>
<%= Html.Hidden("Id") %>
<label for="Title">Title</label>
<%= Html.TextBox("Title") %>
<label for="Body">Body</label>
<%= Html.TextArea("Body") %>
<%= Html.Submit("Submit") %>
<% } %>
And here's the Save action that the view submits to:
public ActionResult Save(int id, string title, string body)
{
var post = id == 0 ? new Post() : _repository.Get(id);
post.Title = title;
post.Body = body;
_repository.Save(post);
return RedirectToAction("list");
}
I don't like the Views to become too complex, and so far I have tended to have separate views for Edit and Add. I use a user control to store the common elements to avoid repetition. Both of the views will be centered around the same ViewData, and I have a marker on my data to say whether the object is new or an existing object.
This isn't any more elegant than what you have stipulated, so I wonder if any of the Django or Rails guys can provide any input.
I love asp.net mvc but it is still maturing, and still needs more sugar adding to take away some of the friction of creating websites.
I personally just prefer to use the if/else right there in the view. It helps me see everything going on in view at once.
If you want to avoid the tag soup though, I would suggest creating a helper method.
<%= Helper.ProfessionField() %>
string ProfessionField()
{
if(IsNewItem) { return /* some drop down code */ }
else { return "<p>" + _profession+ "</p>"; }
}
You can specify a CustomViewData class and pass the parameters here.
public class MyViewData {
public bool IsReadOnly { get; set; }
public ModelObject MyObject { get; set; }
}
And both views should implement this ViewData.
As a result you can use provided IsReadOnly property to manage the UserControl result.
As the controller uses this, you can unit test it and your views doesn't have implementation, so you can respect the MVC principles.