MVC, use same View for multiple profiles - asp.net-mvc

I'm making a game website and using GiantBombs.com API. I've finished a search function and on a search I get the results in a table.
I want every row to be a link to the "Game Profile" i want on the site.
My issue is I can't figure out how to give every game a unique URL, only using 1 View.
E.g:
Localhost/Gameprofile/XXX-XXX - where X is the "ID" property of the game on GiantBomb
For my search function I could use this which generate a URL based on the search.
<form method="get" action="/URL">
<input id="searchField" name="search">
<input type="hidden" id="myValue" value="#ViewBag.sq" />
However, I can't figure out how to do this on a Table.

If you have all of the information about each game stored in a database table then you can do something like this:
You need to pass the games ID as a parameter to the function that loads your page. For example:
//One Page
public ActionResult Gameprofile(int ID)
{
//Query your database, to return only the related rows.
//To do this you can refer to the parameter you just passed in.
return View();
}
You can call the function from your index page like so:
#Html.ActionLink("Gameprofile", "ControllerName", new { .ID = "myValue"});
I'm not entirely certain that this is what you're aiming for, but hopefully it helps.
If you're new to mvc, there's plenty of help and advice on stack overflow and the MSDN.

Related

ActionMethod I just created cannot be found

So I've created a table to hold extra information for all authenticated users. This table also links up to the many others in my db. This table is hooked up to asp.net identity through the user id although there are multiple fields which share the same information as the membership tables (email and username as well). Unfortunately there was a bug that erased some of this membership data from the users table I added and not the identity tables themselves. The bug itself has been since been fixed, however I am trying to create a way to retrieve this lost information from the membership tables. The way I went about doing so was by adding a button to the edit screen of the users (Not the usersadmin page but the users table I added). My code for the button taking me to the action looks like this:
Button to action
The UserReset Action code looks like this:
UserReset Action Code
The trouble I am having currently is actually being able to call to this action (or even open the edit page at this point). Every time I try to load the page it throws a "Public Action Method not found in controller" error. I feel it's a rookie mistake on my end but can anyone please tell me what I am doing wrong?
I'm going to hold my tongue on the backstory and just answer the question:
So, you have two major things I found. The first is the CSHTML (but not the direct cause of your current specific error). See farther below for the CSHTML suggestions (especially if you run into more problems after the C# Action fixes)
First, your controller. If you look at your UserReset action, you'll notice you decorated it with [HttpPost]. As you said, you can't open the edit page. This is because the edit page action doesn't exist (e.g., the [HttpGet] action at the requested Url). This is what you need:
public class TSTUsersController : IController
{
...
//You need this action to process the get request
[HttpGet]
public ActionResult UserReset()
{
return View("UserReset"); //return the edit form html to the user
}
//this method will handle the button click
[HttpPost]
public ActionResult UserReset( String email )
{
if(ModelState.IsValid)
{
//save the information to the database
//direct the user to some sort of confirmation page
return RedirectToAction("Index", "Home");
}
//return the form with the error messages
return View("UserReset", email);
}
...
}
From what I can tell, you are completely misunderstanding HTML form submission.
The <form></form> element has two main parameters you are missing:
<form
method="POST"
action="#Url.Action("UserReset", 'TSTUsers")" //e.g. POST /TSTUsers/UserReset
... >
...
<button>Submit</button>
</form>
Or, using helpers:
#using( Html.BeginForm( "UserReset", "TSTUsers", FormMethod.Post ) )
{
<button>Submit</button>
}
Now, this would post to the specified action. To add parameters, in your case, your using a non-changing parameter (e.g., the user can't enter an email), so you have two options. You can modify your action parameter to instead designate the parameter (please note, that the user would see this Url upon a non-ajax post, if that matters to you), like so:
<form
action="#Url.Action("UserReset", 'TSTUsers", new { email = Model.Email })"
//e.g. POST /TSTUsers/UserReset?email=example#example.com
... >
...
<button>Submit</button>
</form>
Or, using helpers:
#using( Html.BeginForm( "UserReset", "TSTUsers", FormMethod.Post, new { email = Model.Email } ) )
{
<button>Submit</button>
}
Now, if you would prefer to hide the Url parameter from the request (for whatever reason), then you would instead add a input, with the type of hidden:
<form
action="#Url.Action("UserReset", 'TSTUsers")" //e.g. "POST /TSTUsers/UserReset
... >
<input type="hidden" name="email" value="#Model.Email"
<button>Submit</button>
</form>
Or, using helpers:
#using( Html.BeginForm( "UserReset", "TSTUsers", FormMethod.Post ) )
{
#Html.Hidden("email", Model.Email )
<button>Submit</button>
}

Unable to use multiple Model in MVC based on any conditions

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.

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.

Generating URL through routing, using ID from a form field (ASP.NET MVC)

Say I want to display user details like so:
http://www.mysite.com/user/1
I set a route up like so:
routes.MapRoute("UserDetails", "user/"{id}",
new { controller = "User", action = "Details" });
Then my controller:
public ActionResult Details(int id)
{
User currentUser = _userRepository.GetUser(id);
if (currentUser == null) return View("NotFound");
return View(currentUser);
}
So far so good. Everything works like I expect. Now I also want a form where one can enter the ID to look up then click Submit to get the same result. eg:
<% Html.BeginForm("Details","User",FormMethod.Post); %>
<input type="text" value="" name="id" id="userid" />
<%= Html.Button("Search For User","submit","searchforuser"; %>
<% Html.EndForm(); %>
This is where I'm currently lost. I don't want to just have [AcceptVerbs(HttpVerbs.Post)] and use a RedirectToAction if possible. I just want to take whatever number they input - say 38 - and go to www.mysite.com/user/38
Is this even possible with straight MVC? I'm sure there are jQuery-related ways but so far have had no luck getting anything beyond a basic jQuery alert working so don't really want to waste any more time on it for now.
MVC will automatically match by name query parameters (for GET) or form input files (for POST) to the action parameters by name. Unfortunately, your id does not match the action parameter name, so MVC can't match them. To fix this, you can:
change the id on the <input type="text" value="" name="id" id="userid" /> from userid to id
change the parameter name of the Details action from id to userid (and don't forget to update your route as well)
I just confirmed that at least the first one fixes the issue on MVC2 RC. I don't have MVC1, so I can't check if it works there as well, but as far as I know there are no major differences in how MVC1 and MVC2 match parameters.

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

Resources