maintaning drop down selected state after post back in MVC razor? - c#

In a MVC 4 Web I have drop-down lists with the below sample code:
#(Html.DropDownList("Condition2", new SelectList(Model.Makes, "CCultureId", "CTitle"), "All",new {#class="span3"}))
I have All as a first option in select and on button press, page shows data in it. After post back, drop downs got reset on button press, can you please guide me how to make drop down keeping its state even after page post backs (I understand in MVC4 there are no postback, I m reffering it as a round trip to server).

One way to do it is, in your controller, return the submitted value in the model. This means your dropdownlist should be hooked up to your viewmodel.
ViewModel:
public class MyViewModel
{
// more properties...
public string Make {get;set;}
// more properties
}
Controller:
[HttpPost]
public ActionResult MyAction(MyViewModel model)
{
// do postback stuff
return View(model); // model.Make is set to whatever was submitted and will be returned
}
Html:
#model Models.MyViewModel
#(Html.DropDownListFor(m => m.Make,
new SelectList(Model.Makes, "CCultureId", "CTitle", Model.Make),
"All", new {#class="span3"}))

You can use Viewbag to save the selected item, see blew:
Get Action
[HttpGet]
public ActionResult YourAction()
{
ViewBag.SelectedItem = "";
///
return View(new yourViewModel);
}
Post Action
[HttpPost]
public ActionResult YourAction(FormCollection form,YourViewModel model)
{
ViewBag.SelectedItem = form["Condition2"];
///
return View(model);
}
View
#(Html.DropDownList("Condition2", new SelectList(Model.Makes, "CCultureId",
"CTitle",ViewBag.SelectedItem), "All",new {#class="span3"}))

You can use the ? operator which works like this and use the Selected property of the selectlistitem
Console.WriteLine((2 == 2 ? "true" : "false"));
and then for example
private Entities en = new Entities();
public ActionResult Index(string selectedvalue)
{
List<SelectListItem> selectlist =
en.tblUser.Select(x => new SelectListItem { Text = x.Name, Value = x.Id,
Selected = ( x.Name == selectedvalue ? false : true) })
.ToList();
ViewBag.DropDown = selectlist;
return View();
}
then in the view u simply put this
#Html.DropDownList("DropDownName", (List<SelectListItem>)ViewBag.DropDown))
obviously its not recommended to use viewbag but instead use a model with a list property.

Related

Using DropdownListFor - Value is being set using Jquery, Displayed in Console too, but Null at Controller

Here is the Syntax of My Dropdown.
#Html.DropDownListFor(model => model.DealerIdRef, Model.Ddllist, " Select Dealer ", new { #class = "form-control"})
i want its default selected value and make it read-only so that user can not update selection. For this i'm using Jquery.
$('#DealerIdRef').val('#Session["MyID"]').trigger('change');
$("#DealerIdRef").attr('disabled', 'true');
this is setting the value and also exists in Console
At Controller it is still null
Edit
if i'm making some mistake then please help.
thanks in advance
Your javascript is setting the disabled attribute of the dropdownlist. Disabled form controls do not submit a value so the value of DealerIdRef in your model is its default (i.e. null because its int?).
If you want the value of the dropdownlist to be submitted, do not disabled it.
But based on i want its default selected value and make it read-only so that user can not update selection, then there is no point generating a dropdownlist, and in anycase, you set selected option by setting the value of the property your binding to. That is you set the value of DealerIdRef in the GET method before you pass the model to the view.
Since all you want is to display a value and have it posted back, then include a hidden input for the value and display the text
#Html.HiddenFor(m => m.DealerIdRef)
<div>...the txt you want to display...</div>
There is no point degrading performance by generating a SelectList and extra html when its not needed.
As a side note, your POST method would have throw this exception because you have not repopulated the SelectList in the POST method before you return the view.
I wrote a simple mock your question.
It can work. The simple code is on DropDownController
Here is the Source Code,I Upload to github.
ViewModel
public class DropDownViewModel
{
[Display(Name = "Dealer")]
public int? DealerIdRef { get; set; }
public IEnumerable<SelectListItem> Ddllist { get; set; }
}
Index View
Mock Your Submit action
#model Sample.Models.DropDownViewModel
#using (Html.BeginForm("ShowDDL", "DropDown", FormMethod.Post))
{
#Html.DropDownListFor(model => model.DealerIdRef, Model.Ddllist, " Select Dealer ", new { #class = "form-control" })
<button>Submit</button>
}
ShowDDL View
Show your select data.
#model Sample.Models.DropDownViewModel
<b>Your Select Value: </b> #Model.DealerIdRef
DropDownController
public ActionResult Index()
{
DropDownViewModel model = new DropDownViewModel()
{
Ddllist = GetDDL(),
DealerIdRef = 1
};
return View(model);
}
[HttpPost]
public ActionResult ShowDDL(DropDownViewModel viewModel)
{
return View(viewModel);
}
private IEnumerable<SelectListItem> GetDDL()
{
return new List<SelectListItem>()
{
new SelectListItem()
{
Text = "One",
Value = "1"
},
new SelectListItem()
{
Text = "Two",
Value = "2"
}
};
}

Passing a parameter back to a view after performing a form action?

I have a view that loads a record with a certain record number. Once the page is loaded, it gives the user an opportunity to login for additional information. Once the login logic is performed, I need to return to that same view with the same record number intact. I am passing the record number to the action using a hidden input in the form. What I can't seem to figure out is how to return to that same view and provide it with that record #. The code I am trying below is not working. I know this is MVC 101 stuff but a hint in the right direction would be appreciated, or feel free to scrap my method and suggest something better!
Form in view:
<form action="/MyView/Authenticate/#item.ID" method="post" enctype="multipart/form-data">
<input name="form_id" type="hidden" value="#item.ID">
.....
Form action:
[HttpPost]
public ActionResult Authenticate()
{
int myid = Convert.ToInt16(Request["form_id"]);
.....
return View("Index", new { id = myid } );
}
EDIT:
It turns out that the correct view is being returned, but it is expecting a model item type of "JobSummaryModel" per the Index action result below. So the question I actually need answered is, how do I pass both the record id and this view model to it?
public ActionResult Index(int id = 0)
{
List<JobSummaryModel> jdata;
ViewBag.IsResults = false;
if (id != 0)
{
ViewBag.IsResults = true;
}
jdata = db.Jobs.Where(c => c.ID == id).Select(c => new JobSummaryModel() { ID = c.ID, Name = c.Name, City = c.City, PostalCode = c.PostalCode, JobDescription = c.PositionDescription }).ToList();
return View(jdata);
}
EDIT:
Thanks Reddy, your suggestions worked! My only remaining issue is that when I return to my Index view from the Authenticate action, I do not seem to have my "jdata". Is my Index action result not being rerun when I return the Index view via my Authenticate action? I am coming from a web forms background where, in an instance like this, the Load/Init events would automatically run when a form is loaded. Do I need to bind my "jdata" in the Authenticate action and include it in the viewmodel?
EDIT: Resolved. Changed my "return View" to a "return RedirectToAction" to resolve my final issue. Thanks everyone!
Answer For your after Edit:
All you want to pass to view is a int Id and your List<JobSummaryModel> jdata right?
So create a ViewModel JObSummaryModelHelper
Public class JObSummaryModelHelper
{
public int Id {get;set;}
public List<JobSummaryModel> jdata {get;set;}
}
Now in your controller
public ActionResult Index(int id = 0)
{
JObSummaryModelHelper jobDetails = new JObSummaryModelHelper();
jobDetails.Id = id;
ViewBag.IsResults = false;
if (id != 0)
{
ViewBag.IsResults = true;
}
jobDetails .jdata = db.Jobs.Where(c => c.ID == id).Select(c => new JobSummaryModel() { ID = c.ID, Name = c.Name, City = c.City, PostalCode = c.PostalCode, JobDescription = c.PositionDescription }).ToList();
return View(jobDetails );
}
Now make sure your view is set to expect this new viewmodel
#model JObSummaryModelHelper
carry on with your manipulation......
You are better off creating a ViewModel for this like so:
Create a View Model class i.e.
public class AuthViewModel
{
public int MyId { get; set; }
}
In your View put the following directive at the top:
#model AuthViewModel
In your initial [HttpGet] method return the view model:
[HttpGet]
public ActionResult Authenticate()
{
var model = new AuthViewModel { MyId = 123 };
return View("Index", model );
}
It's best to use Html helpers in your view, so you can change it to this:
#using(Html.BeginForm()
{
#Html.HiddenFor(m => m.MyId)
...
}
The above uses naming conventions to post back to the action that you are on.
Then return it to your view like this:
[HttpPost]
public ActionResult Authenticate(AuthViewModel model)
{
int myid = model.MyId;
return View("Index", model );
}
Then you can output using this razor syntax #Model.MyId
It's really worth doing some tutorials to learn the conventions, a small amount of time invested in this will save you a lot of time in the future.
Instead of
return View("Index", new { id = myid } );
could you do
return Index(myid);

MVC List Null on Postback

My Controller populates my Model with a list with strings that appear in a DropDownList in my View. When the view is posted back to my Controller, that list is suddenly null. Why is it null, and what happened to the list of strings I created?
The list was properly populated and shows up in the View. The remainder of the form elements DO properly post back. For example, selectedName has whatever name the user clicked on. The only thing that is not posting back is nameList.
Here is the relevant part of my model,
public class MyModel
{
[Display(Name = "Selected")]
public string selectedName{ get; set; }
[Display(Name = "Names")]
public List<string> nameList{ get; set; }
}
the relevant Get and Post parts of my Controller,
public class MyController: Controller
{
[HttpGet]
public ActionResult Index()
{
List<string> nameList= getNames();
MyModel model = new MyModel()
model.nameList= nameList;
// Now, model.nameList has a bunch of stuff in it
return View(model);
}
[HttpPost]
public ActionResult Index(MyModel model)
{
if(model.nameList== null)
{
cry();
postOnStackOverflow();
}
return View(model);
}
}
and the relevant part of my View (which is encapsulated inside of a form).
<p>
#Html.LabelFor(c => c.nameList):
#Html.DropDownListFor(c => c.selectedName, new SelectList(Model.nameList), new { onchange = "this.form.submit();" })
</p>
Only the value of the drop down list is posted when you post the form. I assume that your control in question is on a form.
I am not sure why you want to always return to the view you posted from, but you need to repopulate the list:
[HttpPost]
public ActionResult Index(MyModel model)
{
List<string> names = getNames();
model.nameList = names;
return View(model);
}
That is the expected behaviour considering what you have in your view. You need to reload the namelist collection property incase you are returning model to the same view again.
[HttpPost]
public ActionResult Index(MyModel model)
{
if(ModelState.IsValid)
{
// Save and redirect
}
//reload the collection again and return the model to the view
model.nameList=getNames();
return View(model);
}

MVC Dropdownlist returns null to HttpPost

My problem is that I am trying to setup a drop down list and when a new item is selected it will update a table of information that I have but every time HttpPost function gets called the parameter is always null. Here is index function of my home controller:
public ActionResult Index()
{
Project[] projects = db.Projects.ToArray();
List<SelectListItem> dropList = new List<SelectListItem>();
BurndownSprintTable[] TableToShow = db.BurndownSprintTables.ToArray();
for (int index = 0; index < projects.Length; ++index)
{
dropList.Add(new SelectListItem { Text = projects[index].Name, Value = projects[index].Id.ToString(), Selected = projects[index].Selected });
if (projects[index].Selected == true)
{
int ProjectId = projects[index].Id;
TableToShow = db.BurndownSprintTables.Where(x => x.ProjectId == ProjectId).ToArray();
}
}
ViewBag.Projects = dropList;
return View(TableToShow);
}
TableToShow is used to show sprint information per project.
Here is the post function:
[HttpPost]
public ActionResult ProjectUpdate(string strProjectId)
{
return View("Index");
}
I realize this post function will cause an error which I believe I can fix on my own but I need strProjectId to not be null.
Here is the html:
#model IEnumerable<TableauConfigWebService.Models.BurndownSprintTable>
#using (Html.BeginForm("ProjectUpdate", "Home", FormMethod.Post))
{
<h5>#Html.DropDownList("Id", (IEnumerable<SelectListItem>)ViewBag.Projects)
<input type="submit" value="Update" /></h5>
}
There is more to it but the rest of the html is setting up a table for the sprint information which works fine.
I have looked around and found a bunch of posts on this but none of them seem to help. I am new to mvc so I know its probably something simple but I cant figure it out.
Thank you for any help.
Change to this
[HttpPost]
public ActionResult ProjectUpdate(string Id)
{
return View("Index");
}
Or change the control Name to
#Html.DropDownList("strProjectId", (IEnumerable<SelectListItem>)ViewBag.Projects)
Try this simple way , and check it ,
Must be same names are dropdown and model property .
But you can try this simple way
[HttpPost]
public ActionResult ProjectUpdate()
{
**string strProjectId=Request.Form["strProjectId"].ToString();**//Or use Request["strProjectId"].ToString();
return View("Index");
}
#Html.DropDownList("**strProjectId**", (IEnumerable<SelectListItem>)ViewBag.Projects)
or
Simply, you can use FormCollection like,
[HttpPost]
public ActionResult ProjectUpdate(FormCollection collection)
{
**string strProjectId=collection["strProjectId"].ToString();**
return View("Index");
}
#Html.DropDownList("**strProjectId**", (IEnumerable<SelectListItem>)ViewBag.Projects)
And check my code with using break points !
Use the same parametre name at both the place in view and controller.
either change in controller.
public ActionResult ProjectUpdate(string Id)
{
return View("Index");
}
or else change in view dropdown code to this.
#Html.DropDownList("strProjectId", (IEnumerable<SelectListItem>)ViewBag.Projects)
hope this helps...

NullReference error on foreach used to create radiobuttons on POST

I am teaching myself asp .net mvc3. I have a "add property" form which allows user to upload property details to the website. I have been struggling with this error for a long time now.
For simplification, lets consider that I have two tables in my database.
CustomerTypes: The database has 1 Owner, 2 Broker, 3 Commercial etc
Property: This is the table that gets populated by the form.
I use CustomerTypes (and other such tables) to create radio buttons. The user fills the form and selects a choice for "customer type". However, I get an "object reference not set to an instance of an object" error on submit. This is is because "null" is
set for Model.CustomerTypes. However, Model.CustomerTypes is only used to create radio buttons. I am not sure what is wrong. The code is below:
View:
#model Website.ViewModels.AddPropertyViewModel
<fieldset>
<legend>Property</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Property.CustomerType)
#foreach (var item in Model.CustomerTypes)
{
#Html.RadioButtonFor(model => model.Property.CustomerType, Convert.ToInt32(item.Value)) #item.Text
}
</div>
...
AddPropertyViewModel:
namespace Website.ViewModels
{
public class AddPropertyViewModel
{
public Property Property { get; set; }
...
public IEnumerable<SelectListItem> CustomerTypes { get; set; }
...
}
Controller:
public ActionResult AddProperty()
{
AddPropertyViewModel viewModel = new AddPropertyViewModel
{
...
CustomerTypes = websiterepository.GetCustomerTypeSelectList(),
...
};
return View(viewModel);
GetCustomerTypeSelectList functions is:
public IEnumerable<SelectListItem> GetCustomerTypeSelectList()
{
var customerTypes = from p in db.CustomerType
orderby p.CustomerTypeDescription
select new SelectListItem
{
Text = p.CustomerTypeDescription,
Value = SqlFunctions.StringConvert((double)p.CustomerTypeId)
};
return customerTypes;
}
The value in POST is set for Property_CustomerType correctly based on the selection
--- Added further info ---
I start the form as:
#using (Html.BeginForm("AddProperty", "Property", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
...
}
The controller is:
[HttpPost]
public ActionResult AddProperty(AddPropertyViewModel viewModel)
{
if (ModelState.IsValid)
{
//
if (viewModel.File1.ContentLength > 0)
{
var fileName = Path.GetFileName(viewModel.File1.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data"), fileName);
viewModel.File1.SaveAs(path);
}
var property = viewModel.Property;
websiterepository.Add(property);
return RedirectToAction("Index", "Home");
}
return View(viewModel);
}
Here is a screenshot of error:
I have tried submitting the form commenting these radio buttons and it works.
The issue is that CustomerTypes isn't populated when your render the view after posting to the server.
If we look at the flow of actions being performed we see that
You populate the CustomerTypes collection before rendering the
inital page
You post your data back to the server but do not
preserve the CustomerTypes collection (Because there's no need to)
You render the view again but this time without populating
CustomerTypes.
Kaboom!
Populating the CustomerTypes property before you return the view for the second time should fix your problem:
[HttpPost]
public ActionResult AddProperty(AddPropertyViewModel viewModel)
{
[...]
viewModel.CustomerTypes = websiterepository.GetCustomerTypeSelectList();
return View(viewModel);
}

Categories

Resources