How can I pass an altered Model to a Controller from View - c#

I'm new to MVC and having a rough time with this. I have read many posts and books and done tutorials and I am now going to ask the public for help.
My situation:
I am upgrading part of a classic ASP website to MVC. It is the FAQ portion of the website.
I've got a controller called FAQController and a View Result called, Display, that takes in the parameters Year and faqID and then displays the related FAQ information in the view.
I want to be able to have a user rate how helpful the FAQ was by clicking on a set of links or buttons that will look like stars (1-star through 5-star ratings)
I want the onclick event of the buttons to route to an [HttpPost] ViewResult that then stores the rating in a database and returns them to the previous view with whatever selection they made highlighted. So if they click 4 stars after the information is submitted 4 stars would be highlighted.
So I have an int rating property in my model that I want to be able to change in the view, then update to a database, and then display the change once the view loads again.
My question is what is a good way to change the Rating value of the Model before I resubmit the model to the controller?
I see I can use #Html.Hiddenfor(m => Model.FAQRating) to get the value of the first model rating (which by default is 0) but how should I go about setting that value before I resubmit the form to the controller.
Am I even thinking about this correctly? I thought I might be able to add a "rating" parameter to the Display view result but that seemed dumb.

Related

Keeping data across a redirect

I have a page with a form that accepts a list of account numbers into a text box, a bulk search essentially.
This does posts to the server, does a validation exercise and then if sucessful redirects to a display page.
Currently the list is added as a GET variable in the URL to the display page. This is limiting in that it means users can mess with it and larger data sets may be a problem. It also allows for a bypass of the validation but this is accounted for.
I see 2 general solutions which are basically variations of 1 theme:
Save the list to a DB and pass a key to load this to the diplay page.
Save to MemoryCache and again pass the key to the display page.
Based on these options it seems that 1. is better if I need multiple IIS node but needs manual cache cleanup where 2. will clean it's self up but may be a problem if I need to scale. This will be an intranet applcation so scale will probably not be required.
Is there a "industry standard" approach to this class of problem. I'm coming from the winforms world where keeping track of state wasn't an issue.
I don't think you really have to redirect to the display page at all. From the controller that gets the user input and prints the result just return the View that should render the results like:
public class SearchController : Controller
{
public ActionResult SearchForAccounts(string[] accounts)
{
var searchResults = db.Search(accounts);
return View('ResultsView', searchResults);
}
}
If you really really need to redirect, I guess you chould save the results into the application Cache and later if you need to scale you could use a Redis Cache provider for example, but again you should be able to show the required view.
Whether it's Webforms or MVC, I recommend not getting into the pattern of separating validation/processing and results into separate pages.
I'm guessing that if the data is invalid you want to put it back on the page so the user can edit it. (That's a guess inferred from what you're asking.)
You can post the data, and then if the data is valid then the "result" page shows the results. If the data isn't valid then the page can re-render the input form, populate it with the original inputs, and display a validation error. That way the user can modify their original input and try again. (Just be sure to escape/unescape if you're taking user input and reflecting it back onto the page.) That's easier if the form is a partial view (MVC) or a user control (Webforms.)

MVC Dropdownlist not selecting value when passing SelectList instead of full-auto for Title property

I have a MVC 5 application using a lot of the standard features. I have a number of dropdownlists across the app that render properly, except for one.
In the Controller:
ViewBag.TitleLookup = new SelectList(db.TitleLookups, "Title", "Title", person.Title);
return View(person);
In the View:
#Html.DropDownList("Title",(SelectList)ViewBag.TitleLookup,string.Empty)
#Html.DropDownList("TitleLookup", string.Empty)
Both dropdown lists render the options properly, however, the first does not have the properly selected item. The second has the wrong Name so would not be submitted to the server on a post, however it did have the "valid" property indicating the validation was active.
I have stepped through the controller and the SelectListItems are getting built correctly along with the selected property on the proper Item getting set to True.
So to ask a concrete question: Why does the first dropdownlist not render the proper selected item? Is there indeed something crazy about having the property called "Title"?
I can change the datamodel if I absolutely have to, but feels like it should be able to work without doing that.
It looks like you have put in "Title" for the second and third parameters on the select list. Those parameters are for complex objects to select those properties, say Key and Value if you're binding to a dictionary (I'm assuming db.TitleLookups is a list of strings). Instead, try this:
new SelectList(db.TitleLookups, person.Title);
In addition, MVC might have issues with controls named after a ViewData/ViewBag property. See: ASP.NET MVC Html.DropDownList SelectedValue

Pre-populate model value on MVC3 page

I am new to ASP MVC3 and I am trying to make a set of pages for creating and editing sales notes records for customers in our database. On the Customer detail page, I have a table that will display all sales notes for the selected customer and it has a "Create Note" button that goes to a create page for sales notes. How do I pass and pre-populate the CustomerID field on the note with the ID of the customer from the previous page? I searched for an example or tutorial that had this scenario but didn't find one. If you know of a public example a link to it or a direct answer to the question would be greatly appreciated.
You can accomplish this fairly easily with routing parameters. First you need to define the route for the create note action that takes a customer Id. Next, you need to create the action so that it accepts the parameter.
A quick Google search or "ASP.NET MVC Routing Parameters" turned up this URL which explains it very well:
http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/asp-net-mvc-routing-overview-cs

ASP.NET MVC UpdateModel binding with a Hierarchy of Collections

I have the following Model design.
Template contains a list of Categories.
Categories contains a List of Items.
Thus there is 3 layer hierarchy. Because the UI design requires that all 3 levels be created on 1 page, I have had to write some of my own code to get this working. It looks as follows:
I can get it to submit back to the Create Action Method and the FormCollection looks as follows.
The problem I am having is that the UpdateModel works for the Template and Category level but the Items are not populated for the Categories. The Html looks as follows. As you can see, I have used the Category[guid_value].Items[guid_value] syntax for id. Shouldn't it figure out the binding automagically based on that?
Is there something I am missing or have to do in order to get the binding to work?
if you want your html to bind correctly to your model you have to pay some attention to html you render. The problem that i can see with your html is
<input type='hidden' value = 'Items.Index' value= 'some_guid' autocomplete = 'off'/>
with this html model binder will try to bind Items as children of Template object where it will not find any property named Items and these values will not be bound to the model. you have to change your hidden field to
<input type='hidden' name = 'Categories[category's guid].Items.Index' value = 'some guid' autocomplete = 'off'/>
and you have to just call updatemodel in your action method like
UpdateModel(yourobject);
i have not tested this code but i am more than certain that changing your html this way will get you sorted.
#Mlchael Grassman you don't have to use integer based id's to bind collection anymore. plz read steve's post for more information. Actually you don't need GUID either but a random number that is unique in page's context provided that you put an extra hidden field with name index and value set to above mentioned random number. I have blogged about Master detail form in asp.net mvc using (and modifying) BeginCollectionItem method written by Steve. in part one of this blog series i simply showed how you can dynamically add fields of your detail record on client side without ajax call. In second part i brought the editor template of detail record to jquery templating engine and rendering it on client side as it would appear if rendered through ajax call.
By default MVC uses the following convention for naming.
Category[0].Items[0]
Category[0].Items[1]
Category[1].Items[0]
Category[1].Items[1]
You can include your own Update by using the following TryUpdateModel. This woud probably need some sort of loop but should get you started.
TryUpdateModel(Category[Guid].Items[Guid], "Category[Guid].Items[Guid]", null, new string[] { "ExcludedPropery1", "ExcludedPropery2", "ExcludedProperyN", });

Sending collection of items in ASP.NET MVC

I've got two classes in my MVC project Order and Product.
Because Product can be ordered many times and Order can have many products I've got third entity which is OrderedProduct. It joins those two entities in many-to-many relation.
Now what I'm trying to do is to let user to make an order by putting products from the drop down list to the box and then to save my order. Also client have to fill some fileds in the Order entity such as Address data etc. All I want is to have it all on one single page. User can add as many items from dropdown as he like, then he can add whole order.
To make it easier to visualize look at this picture:
Now the problem is how to implement such behaviour in my MVC app. Should I build a ViewModel that combines Order class and list of Product or use partial view for Product classes?
Also which is my main problem, how can I (in elegant way) retrieve the full list of chosen products or at least product id's in the controller after POST request? In this case how can I specify that what I'm sending is a collection of ids? It's simple to add one object, but what about whole collection?
This is the place when I do not fully understand asp.net MVC, so please give me some bright ideas ;) Greetings to you all, thanks in advice for all your answers!
The desired interface seems a bit confusing to me but here's how you can handle these things.. modify to your desire. I'm going to assume OrderedProduct is an object for ordering that contains a Product ID and a quantity and that you want to be able to modify them all at the same time.
Make Order your ViewModel. Given that it has a List<OrderedProduct> property called OrderedProducts:
Create a small editor control with a ViewModel of OrderedProduct. No form, just a textbox/dropdown/whatever bound to the product name property and a textbox bound to the product quantity. Important: put this control in views/shared/EditorTemplates and call it OrderedProduct.ascx.
Give your Order object a property called NewOrderedProduct of type OrderedProduct.
In the form for the Order view do: <%=Html.EditorFor(m=>m.OrderedProducts)%> this will give you an editable list current items in the order.
After that do: <%= Html.EditorFor(m=> m.NewOrderedProduct) %> this is where you can add new items.
Have the [POST] action take a type of Order.
Now when it submits if the NewOrderedProduct property is valid you can add it to the OrderedProducts list and redisplay. You can add as many as you want this way and they will all autobind.
Have a separate submit button in the form for submitting the order. Check for the existence of that button's name in the [POST] and submit all at one time.
This gets you a straight HTML working version. From there you can Ajaxify it if you want.
Edit
Updated to reflect the function of the OrderedProduct object and correct the type the post accepts

Categories