Unable to use multiple Model in MVC based on any conditions - asp.net-mvc

I am creating a voting mechanism for my MVC application. user will be able to vote only after loged in. I have totally 3 tables tblQuestions(to populate the questions), tblAnswers(to populate the answers), tblQuestionAnswerUserResponses (to populate the user response.)tblAnswers have relation with tblQuestions. I have used the following code in the container in the HttpGet. This is my controller code.
[HttpGet]
[ActionName("VotingResult")]
public ActionResult VotingResult(int personid)
{
List<Voting_Questions> QuesList = EpDObj.PopulateQuestions(); //Populate the list of questions
CountofQuestionsDisplayed = QuesList.Count;
ViewBag.Questions = QuesList; // Storing the list of questions in the viewbag
List<Voting_Answers> Answers = EmcObj.Voting_Answers.ToList(); //Populate the list of answers
return View(Answers);
}
I am using the Voting_Answers as model in my view My view is
#model IEnumerable<EmployeeManagementDAL.Voting_Answers>
<h2>VotingResult</h2>
#using (Html.BeginForm())
{
<div>
#foreach (var a in ViewBag.Questions)
{
<h4>#a.Questions</h4>
<div>
#foreach (var b in Model)
{
if (b.QuestionsID == a.id)
{
#Html.RadioButton(b.AnswersOptions, new {Answerid= b.id, Questionid=a.id }) #b.AnswersOptions
}
}
</div>
}
</div>
<br/>
<div >
<input type="submit" value="Vote Now!!" onclick="return confirm('Are you sure you want to submit your choices?');"/>
</div>
}
When the user go to this page for the very first time there will be no options selected. after selecting the options the values an clicking Save button will save the details to the third table and then he comes out of that page. Now if for the second time he reaches that page for editing, I want my page to render with those values in my tblQuestionAnswerResponses i.e I guess my model class of tblQuestionAnswerResponses to be used. In that case can i use the same page for both cases i.e when the user vists the page for first time and also when second time the page is visited. Can I use multiple Model in MVC based on conditions in my View.

Your ActionName attribute is unnecessary, as you have specified the same name that your action already has.
It would be cleaner to use a ViewModel instead of using the ViewBag. For starters, you'll get strong typing in your view, and it will also lend itself to easier testing.
If you make a ViewModel that represents what you want your view to display, then you can map back and forth between it and your domain models in your controller actions, and let them do the heavy lifing.

Related

Partial Views on mvc create view that use a dropdown list to populate the partial view's view bag is this possible in mvc?

can a Partial Views on mvc create view that is using a dropdown list that sends value from the dropdown list to a function that creates a list based on the dropdown list value selection, That is then stored in a view bag for the partial view.. Can this be done in mvc and can it be done on create view of a mvc form?
I can see how something this would work in the edit view because the dropdown list value has already been selected when the page loads.
But on a new Create view record nothing is selected so the list function has a null value
Are partial views only for forms that have data pre-populated in them?
Update:
I have a create view that was created by the visual studio wizard. It has both a post and get under the create. When the user in the create view. I have a dropdown list on the page form with other fields but on load of that new create page it is empty. Unfortunately for me I wanted my partial view to to get populated with a list of data that gets sent to a view bag after the user make a selection from the drop down list.
I think what I am asking to do can only be done with webforms as mvc can handle dynamic data all that well it seems. And since when the page loads the dropdown has no value.. the list can't built so there is a null value error as well as and empty list if I hard code a value in the drop down list.
Here is my Code in these different attempt threads with different veration of my code documenting my many attempts. As I have comcluded it is not possible sadly.
Can a Drop Down List Trigger A Partial View To Update on A Create View Form In mvc?
Null view bag and partial view
Populating Partial Views using mvc
Updating a Partial View in MVC 5
So with help from Matt Bodily You can Populate a Partial View in the create view triggered by a changed value in a drop down list using a view bag and something called Ajax. Here is how I made my code work.
First the partial view code sample you need to check for null data
_WidgetListPartial
#if (#ViewBag.AList != null)
{
<table cellpadding="1" border="1">
<tr>
<th>
Widget Name
</th>
</tr>
#foreach (MvcProgramX.Models.LIST_FULL item in #ViewBag.AList)
{
<tr>
<td>
#item.WidgetName
</td>
</tr>
}
</table>
}
Populating your View Bag in your controller with a function
private List<DB_LIST_FULL> Get_List(int? VID)
{
return db.DB_LIST_FULL.Where(i => i.A_ID == VID).ToList();
}
In your Create controller add a structure like this using the [HttpGet] element
this will send you data and your partial view to the screen placeholder you have on your create screen The VID will be the ID from your Drop down list this function also sends back the Partial View back to the create form screen
[HttpGet]
public ActionResult UpdatePartialViewList(int? VID)
{
ViewBag.AList = Get_List(VID);
return PartialView("_WidgetListPartial",ViewBag.AList);
}
I am not 100% if this is needed but I added to the the following to the ActionResult Create the form Id and the FormCollection so that I could read the value from the drop down. Again the Ajax stuff may be taking care if it but just in case and the application seems to be working with it.
This is in the [HttpPost]
public ActionResult Create(int RES_VID, FormCollection Collection, [Bind(Include = "... other form fields
This is in the [HttpGet] again this too may not be needed. This is reading a value from the form
UpdatePartialViewList(int.Parse(Collection["RES_VID"]));
On Your Create View Screen where you want your partial view to display
<div class="col-sm-6">
<div class="form-horizontal" style="display:none" id="PV_WidgetList">
#{ Html.RenderAction("UpdatePartialViewList");}
</div>
</div>
And finally the Ajax code behind that reads the click from the dropdown list. get the value of the selected item and passed the values back to all of the controller code behind to build the list and send it to update the partial view and if there is data there it pass the partial view with the update list to the create form.
$(document).ready(function () {
$('#RES_VID').change(function ()
{
debugger;
$.ajax(
{
url: '#Url.Action("UpdatePartialViewList")',
type: 'GET',
data: { VID: $('#RES_VID').val() },
success: function (partialView)
{
$('#PV_WidgetList').html(partialView);
$('#PV_WidgetList').show();
}
});
This many not be the best way to do it but this a a complete an tested answer as it work and it is every step of the process in hopes that no one else has to go through the multi-day horror show I had to go through to get something that worked as initially based on the errors I thought this could not be done in mvc and I would have to continue the app in webforms instead. Thanks again to everyone that helped me formulate this solution!
No, partial views do not necessarily have to be strongly typed, if that's your question. You can have a partial view with just html markup.

How can I emulate model binding behaviour when rendering an ActionLink?

In the following code, the get action returns a betting card for a given race date, and the post I use the post action to transform properties of the bound model to route values for the get action.
Essential aspects of the Details View:
#using (Html.BeginForm("Upload", "BettingCard",
FormMethod.Post, new { id = "uploadForm", enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true, "The upload was unsuccessful. The following error(s) occurred: ")
<div id="date-selector">
<div id="ymd">
#Html.LabelFor(model => model.RaceDate)
#Html.DropDownListFor(model => model.RaceDay, Model.YmdLists.Days)
#Html.DropDownListFor(model => model.RaceMonth, Model.YmdLists.Months)
#Html.DropDownListFor(model => model.RaceYear, Model.YmdLists.Years)
<input type="submit" value="Upload for this date" />
</div>
</div>
#Html.Telerik().Upload().Name("UploadedFiles")
}
Essential aspects of the controller code:
[HttpGet]
public ActionResult Details(int year, int month, int day) {
var model = new BettingCardModel
{
ResultMessage = "No betting card was located for the selected date."
};
DateTime passedDate;
if (!DateTimeHelper.TrySetDmy(year, month, day, out passedDate)) {
ModelState.AddModelError("", "One or more values do not represent a valid date.");
return View(model);
}
model.RaceDate = passedDate;
var bettingCard = _bettingCardService.GetByRaceDate(passedDate);
model.MapFromEntity(bettingCard);
return View(model);
}
[HttpPost]
public ActionResult Details(BettingCardModel model)
{
return RedirectToAction("Details", new { year = model.RaceYear, month = model.RaceMonth, day = model.RaceDay });
}
A good deal of the above code is experimental and diagnostic, so I'd like to avoid getting into a review of code that works, and rather concentrate on what I need to achieve. In the Details view I only need one 'command', being 'Display for Date', so I get off easily by using the submit button and the http post takes care of model binding. However, in the Upload view, I need two commands, being 'Display for Date' and 'Upload for Date', so I would like to make the 'Display for Date' operate strictly with the get actions, and only use a post action to submit an uploaded betting card for the date.
My problem is that when I make the 'Display for Date' command use an ActionLink instead of a submit, using model.RaceDay etc. as routing values, the URL parameters passed to Details all still contain their initial values, not values set by the user in the dropdowns. It seems the model binding code (whatever that may be) is not invoked for action links. What could I do here to avoid need a post just to do that binding?
I realise this probably not a direct model binding issue, but I don't know how else to express my question. When elements 'bound' to model properties are rendered, they have a bit more on their side than a simple input, say, and some basic styling, but something is 'built' around that input with lots of metadata. I would like some way to use that metadata to map to a URL when a get link on the page is clicked.
The problem you're having is that all of the model data and metadata is generated on the server dynamically and given to the client as static content. The binding is only aware of a change to the Model once it is submitted to the Server. All of that model metadata is static on the client side, using pure .NET it will have no way to know when a user changes a value in the drop-down to also change that value in a static anchor tag, which is what the ActionLink renders to. The answer is to use javascript. There are many many way to accomplish what you're trying to do through javascript. You could potentially write a custom HtmlHelper class to generate the javascript for you. However if you don't want to use javascript then you will HAVE to do a post to get the data the user selected to the Server.
If you're trying to avoid having to re-write code then you can create a partial view for the contents of the form and embed that in two separate views. Another thing you could try is to detect which button was pushed by having two submit buttons with the same name like so:
<input type="submit" name="command" value="Update" />
<input type="submit" name="command" value="Display" />
Then in your Controller in the [HttpPost] action you can detect which was pushed via the Request.Forms like this:
[HttpPost]
public ActionResult Details(BettingCardModel model)
{
if (Request.Forms["command"].Equals("Display"))
{
return RedirectToAction("Details", new { year = model.RaceYear, month = model.RaceMonth, day = model.RaceDay });
}
// Do your update code here...
return // Whatever it is you return for update.
}
hopefully this helps you.

Passing form data back to a controller

I am running into an issue with a parameter not getting the value from the form data. It is showing the correct number of items (i.e. if the user select 5 options, the list contains 5 items) in the List but all values are zero. Below is my from my HTML view:
#using (Html.BeginForm())
{
#Html.HiddenFor(s => s.SOWId)
foreach (LabelTable.Domain.Entities.Option option in ViewBag.Options)
{
<div class="wizard-section" id=#option.Level>
#Html.RadioButton("["+(option.Level-1)+"].OptionId", option.OptionId) #option.OptionName
</div>
}
<div class="buttons">
<input type="submit", value="Continue", class="button"/>
</div>
}
Here is my controller method:
[HttpPost]
public ViewResult Wizard(StatementOfWork SOW, List<int> OptionIds)
{
//do something
}
OptionIds contains the following upon posting:
[0] = 0
[1] = 0
[2] = 0
and so on...
What I am trying to do is create a form where the user is presented with some options to select from (this form is one section of a wizard).
There are 5 level (or more) of options. All data for the form is sent to the view via the ViewBag.Options. All levels are hidden except level 1. Upon making a selection on level 1 the next level shows and so on. The form only posts back the options selected via each level. Originally I was doing this with mulitple post backs to the server but I did not like that (to many round trips)
I plan to add the options selected in each level to the SOW model which I am passing from view to view of the wizard.
Your View code is a bit confusing, but as far as I understand, you want the ModelBinder to bind your radiobutton values to the OptionIds list upon posting. In that case, the names of your radiobuttons should be OptionIds[0], OptionIds[1], etc. So again, I am not sure what the Level property is, but I assume you want something like this:
#Html.RadioButton("OptionIds["+(option.Level-1)+"]", option.OptionId)
Try replacing :
#Html.RadioButton("["+(option.Level-1)+"].OptionId", option.OptionId)
with:
#Html.RadioButton("["+(option.Level-1)+"]", option.OptionId)

ASP.NET MVC Filtering results in a list/grid

For some reason I'm stuck on this. I need to filter results from a View based on a DropDownList in the same view. The basic idea is this: I have a list of providers that belong to various partners, but the provider list contains ALL the providers together (for all partners). I need to be able to display the providers by partner when someone wants to see just that partner (otherwise, the default listing will be ALL providers). My view currently is the "default" (showing all), but for some reason Im sitting here staring at the monitor (for the last 2 hours!) trying to figure out how to filter these results.
Any suggestions where to start/how to do it?!
EDIT: If you want to do this with jQuery and AJAX (which will provide a better user experience because only the subdivisions list will refresh), see this tutorial.
If I understand correctly, you basically want to do a WebForms-style postback.
Let's say you have a control with countries and country subdivisions (e.g. states, provinces, etc). When the country changes, you want the appropriate subdivisions to display.
So this would be view:
<% using (Html.BeginForm()) { %>
<%=Html.DropDownList("Address.CountryId", new SelectList(Country.GetAll(), "Id", "Name"), new { onchange = "this.form.submit();" })%>
<%=Html.DropDownList("Address.CountrySubdivisionId", new SelectList(CountrySubDivision.GetByCountryId(Model.CountryId), "Id", "Name"))%>
<input type="submit" name="btnSubmit" value="Submit"/>
<%} %>
This is the key to getting the dependent list to filter:
new { onchange = "this.form.submit();" }
And in the controller, you'd have something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ViewResult Index(string btnSubmit)
{
if (btnSubmit == null)
{
// return the view displayed upon GET
}
else
{
// process the submitted data
}
}
In the above code, if the form submission was triggered by changing the value in a dropdown, btnSubmit will be null. Thus, the action you are POSTing to can tell whether or not the user meant to finalize her changes.
To add upon the earlier answers.
To create a drop down (in ASP .NET MVC 3) I did the following:
Add code to Index.cshtml
#using (Html.BeginForm())
{
#Html.DropDownList("EmployeeId", (SelectList)ViewData["EmployeeId"])
<input type="submit" name="btnSubmit" value="Submit"/>
}
Add code to YourModelNameController.cs in the default ActionResult for Index()
public ActionResult Index()
{
//create a selectlist
var employeeList = from el in db.Employee select el;
ViewData["EmployeeId"] = new SelectList(employeeList, "EmployeeId", "TmName");
return View(modelName);
}
There are many ways to skin this cat. Here's one.
Enclose your DropDownList in a form with METHOD=GET.
<form action="" method="get">
<select name="provider">
<option>1</option>
<!-- etc -->
</select>
</form>
Then, in you controller, filter based on the value of provider that was passed in. Remember to treat it as a Nullable parameter so that you can have some kind of behavior when it's empty.
Without posting some of your current code, it's tough to get much more specific than that.
Let's assume that you're probably passing a model to the view and that model is a list or IEnummerable of partners. What you want to do is restrict the list. In order to do that add a drop down list in the view and fill it with some possible partners. This can be done either by putting a list in ViewData or expanding the model passed back to the view. Both have advantages. Now when you change the drop down reload the page but append a parameter which is the filter. In the controller check for that parameter in the action, if it isn't present then return an unfiltered list, if it is then apply a filter and return the list. The view will just dumbly display whatever you give it.
As for the filtering you might want to try using LINQ.
You probably want a parameter to your controller action, maybe a (nullable?) id of the provider, to filter the results already when you get them from DB. Then just use the same view to list them, and request a new list if the dropdownlist changes.
Best solution I know is that one.
http://gridmvc.codeplex.com/SourceControl/latest

Parsing Form Post Values From a Table in ASP.NET MVC?

Ok, I'm an MVC newbie coming from a webforms background, so please excuse any ignorance here. Here is my scenario. I've got a table consisting of a list of applications and associated permissions. Each table row consists of 3 pieces of information: a checkbox, some text describing the row, and a dropdown list allowing the user to select the appropriate permission for the application. I want to post this data and only work with the rows in the table which were checked (the id of the row is embedded as the checkbox name). From there, I want to grab the selected value from the DropDownList, and call the necessary code to update the DB. Here is my View page's code:
<%foreach (var app in newApps)
{ %>
<tr>
<td><input type="checkbox" name="AddApps" value="<%=app.ApplicationId %>" /></td>
<td><%=Html.Encode(app.ApplicationName)%></td>
<td><%=Html.DropDownList("AppRole", new SelectList(app.Roles, "RoleId", "RoleDescription"))%></td>
</tr>
<%} %>
How would I retrieve the appropriate values from the FormCollection when I get to the controller on form post? I have done this in the past when I only had checkbox values to retrieve by just calling Request.Form["CheckBoxName"] and parsing the string.
Or am I going about this entirely wrong?
You are halfway right in order to post your data that the controller can read the info it must be inside a form as so :
<% using(Html.BeginForm("Retrieve", "Home")) %>//Retrieve is the name of the action while Home is the name of the controller
<% { %>
<%foreach (var app in newApps) { %>
<tr>
<td><%=Html.CheckBox(""+app.ApplicationId )%></td>
<td><%=Html.Encode(app.ApplicationName)%></td>
<td><%=Html.DropDownList("AppRole", new SelectList(app.Roles, "RoleId", "RoleDescription"))%></td>
</tr>
<%} %>
<input type"submit"/>
<% } %>
and on your controller :
public ActionResult Retrieve()
{
//since all variables are dynamically bound you must load your DB into strings in a for loop as so:
List<app>=newApps;
for(int i=0; i<app.Count;i++)
{
var checkobx=Request.Form[""+app[i].ApplicationId];
// the reason you check for false because the Html checkbox helper does some kind of freaky thing for value true: it makes the string read "true, false"
if(checkbox!="false")
{
//etc...almost same for other parameters you want that are in thr form
}
}
//of course return your view
return View("Index");//this vaires by the name of your view ex: if Index.aspx
}
This site gives more details on how to handle the dropdownlist helper:
http://quickstarts.asp.net/previews/mvc/mvc_HowToRenderFormUsingHtmlHelpers.htm
Request.Form will still work, except that your checkboxes all have the same name.
So one way would be to give the checkboxes distinct names, e.g. "AddApps-app.id", and use Request.Form.
However, a more elegant and testable way is to use list binding.
In this model, you give your form elements a certain structured name, and the default model binder will wrap each set of form elements into a list of typed records in the controller. This is fully explained in this blog post.
The advantage here is that your controller deals only with instances of the application type, and hence has no implicit dependency on the way the view is structured. Therefore, it is very easy to unit test.

Resources