How to preserve text during a postback with ASP.NET MVC 3 - asp.net-mvc

I have a Product edit screen. The user can select a Vendor for the Product. To do this, I display a jQueryUI dialog box which allows them to browse for and select a Vendor. When the user selects the Vendor, I update a hidden VendorID input on the page, which is part of my page's model. I also update several divs with details about the Vendor they have selected. These are for display purposes only--only the id is needed to persist the selected Vendor.
This all works fine and dandy except when there is an error on postback, in which case I redisplay the same view. ModelState takes care of preserving all my form fields (including the hidden VendorID). However, my divs with the Vendor text are (of course) empty since they're not posted to the server.
I first went down the path of creating hidden fields for each of my Vendor display fields and putting them on the model. Then the hidden fields survive the postback, but that doesn't solve the problem of actually redisplaying the text on the screen.
The three options I can think of are:
On postback, if there is an error, go to the database, fetch the Vendor using the supplied VendorID and re-populate the model with the text I want to display.
Use RenderAction and have an action which renders the details of the selected Vendor.
Use readonly textboxes instead of divs to display the Vendor details.
None of these feel very satisfactory to me. I feel like I might be missing an obvious solution. Are there any better solutions?

I would suggest you not have the extra Vendor information come down as part of the main page. Create a javascript function showVendorInfo(). When called, if the VendorID hidden input has a value, it gets the relevant Vendor information via AJAX and displays it, using an AjaxGetVendorInfo action method. Call this function from two places:
In document.ready()
after a Vendor is selected with jQueryUI display.
Now, this would be in an action method. You could, if you expect your users to have latency issues, do the following to avoid some ajax calls: In the view check if you know the VendorID; if so, call Html.RenderAction call the same AjaxGetVendorInfo action method from the view.
A bonus to this is that it avoids what I have found to be a big no-no: Including both display-only values and model-binding values in your ViewModel. This makes for a very confusing ViewModel, especially when there are validation errors. [Getting on soap box] It's best to have your ViewModel to just have properties intended for modelbinding, for your state. Put list values, extra display information, etc., into ViewData or have them show up via AJAX.

Related

Why are my dotnet 5.0 mvc form fields retaining their input values on post?

I have an dot net 5.0 mvc page which takes a model object (ClassFoo) which when constructed generates an instance of (classBar). ClassBar has various properties (FieldA, FieldB, FieldC) all are strings.
The Views content is all in a form and the form's input fields are all from ClassFoo.ClassBar's various properties. Initially, when the page is accessed, all form input values are empty. However when I put data into them and then submit the form, the form values are still there when the page loads. However I don't understand why this is because I'm explicitly creating a new model during the controller operation but I am not actually populating the Model.ClassBar with the content from the post before I return model to the View for generation.
What I would expect is that all of the form fields would be empty however that is not the case. I know if asp.net the form values are stored and restored automatically but I didn't think that happened in mvc.
After looking into ModelState recommended by Nick Albrech in the comments I reviewed the hint associated w/ the HtmlHelper.TextBoxFor() which states the following:
... Adds a "value" attribute to the element containing the first non-null value found in: the ActionContext.ModelState entry with full name, or the expression evaluated against ViewDataDictionary.Model. See [IHtmlHelper.NameFor] for more information about a "full name".
So effectively what's happening is similar to what I thought asp.net mvc wasn't doing in that it populates the ModelState from a get/post request with the name and values of the form being submitted. Then based on the use of these helper functions (and also asp-for attributes used in razor views views), it either provides values from the saved model state form values OR the model passed to the view. Note: this does not seem to work if you set the value of an input element = #Model.[someProperty]
The take away from this is that you do not necessarily need to update your model object with content from the previous form submit in order to have the page populate the form contents back to the screen. Allow asp.net mvc to do the manual tasks by making use of these razor helpers.
Shoutout to Nick for the assist on this one. A solid member of the stackOverflow community.

Pre-populate ListBox / MultiSelectList with selected items

Is there a way to pre-populate a MultiSelectList with selected items?
Example:
I have a single View that has the following ListBoxFor that will cause the page to update what it's displaying by allowing filtering of Model.Companies.
#Html.ListBoxFor(m => m.SelectedCompanies, new MultiSelectList(Model.Companies, "IdString", "CompanyName")
What I'd like to have happen is after the update, the MultiSelectList will have the items that were selected before the page updated and refreshed. Does that mean I need to return SelectedCompanies with what was selected, or is there another way?
I am using the javascript library Chosen for usability of the ListBox on the client side, but I don't think that this affects what I'm trying to do.
Sometimes, JS libaries can interfere with your desired results. I can't speak for Chosen JS library, but inspect the markup and see how it renders. As long as it still has the listbox on the client (it must have some input element defined somewhere; my guess it hides it and updates the values as they are selected), then yes it should integrate fine.
However, when the controller posts back, you have to repopulate the Model.SelectedCompanies property with whatever values came back from the POST operation to the controller. The property should still have the selected companies if you return a View from the POST operation. If you are using a RedirectToAction instead, you'd have to store the selections in TempData.

Where do form fields in ASP.Net MVC take their values from?

I understand that fields such as Html.TextBox() accept two values, the first one being the name and the second one being the value. And so does Html.TextArea(). But in a case where the form is submitted as AJAX and the div where the form is placed is replaced with a view from the server, the form fields insist on taking the previous values. An image is worth a thousand words:
image http://img132.imageshack.us/img132/4171/aspnetmvcbug.png
I've checked everything on the controller and the model and the image is from debugging the view itself. The model is empty but the fields generated from it take the value of the previous submission.
The postback data is held in the ModelState. The built in HtmlHelper methods will look for values stored in the model state based on the name of the form element when rendering their content.
Check the View.ModelState property. Forms can grab values from there in certain circumstances.
Do you have an entry ViewData["Body"]? MVC will also attempt to bind a control to a ViewData item based on the name.

ASP .NET MVC: Html.Radiobutton onclick -- set ViewData[""]

I'm new to ASP .NET MVC and to web programming in general.
I'm wondering if there is a way to set ViewData variables when a radiobutton is selected -- but before the page is submitted.
Maybe I'm barking up the wrong tree but what I'm trying to do is create a form where new fields are added based on which radio button is selected. So what I want to do is when a radiobutton is clicked it sets a ViewData variable and based on that ViewData variable a different partial view loads the appropriate fields below the current field.
I imagine there must be someway of doing a onclick="some C# function that sets ViewData(args)"
Thanks
There are a couple of ways you could go about this.
1) You could have an Ajax form where through Javascript you post the form back and check to see if it's an Ajax Request, there by returning a partial view to a div that you specify.
2) Post the form as is and check server-side to see if the radio button was clicked, and thus redisplay the form with the new options visible.
If you take the first approach it would be easy enough to fall through to the second one for those without Javascript enabled.
There aren't really "onclick" events as I'm assuming you are used to from Webforms, you would basically have to roll your own Javascript to handle such things. Once you do a few, I think you'll find it's really not too bad, with the benefit that you'll have more control over what you're doing and through that gain a better understanding of the larger picture.
ViewData only exists, and only exists server-side, for the lifetime of the request. So, once the page is rendered the object no longer exists.
Some alternate approaches you can take:
1 - Use client-side Javascript to add a form and inputs as necessary. More info here:
ASP.NET MVC & JQuery Dynamic Form Content
2 - Pre-render the new form, but hide it via CSS, and unhide it when the appropriate radio button is clicked. More info here:
expand collapse html field Firefox
3 - Use AJAX to render the new form when the appropriate radio button is clicked. More info here:
http://www.asp.net/learn/mvc/tutorial-32-cs.aspx

Persisting data from multiple forms in ASP.NET MVC

I have two forms on one page: a results form and a search form. The search form uses a partial view because it is displayed on several different pages. I want to be able to persist the data in the search form regardles of which button on which form the user clicks. The problem is that when the user clicks on a link or button from the results form, only the form values from the results form are posted, the values from the search form are not included. How can I maintain the values in the search form even when it is not the form that is submitted? I do not want to use any type of session state to maintain the form and I dont want to write the search values in hidden fields in the results form. I just want to be able to post them with the form values of the results form so that the users search criteria can be maintained accross any page that displays the search partial view. What am I missing?
The first thought that occured to me is to remove the form wrapping the search control and just let it be rendered into the form with the results data. I worry here about naming conflicts. What happens when the search from has a control with the same name as the results form, wouldn't this cause a naming conflict? I suppose that this could just be managed manually to ensure that there are unique names whenever rendering partial views into other views, perhaps even going so far as to prefix values with the partial view name, but that reminds me of the ugliness that is INamingContainer in web forms - plus makes for cumbersome field names in your model.
Is there some sort of elegant solution that will allow a form to persist state that I am missing? Thanks!
Normally, I persist the search criteria on the server side when the search is performed. If the user changes the search criteria after performing the search, then posts the form any changes are, of course, lost but that's arguably correct behavior since the search wasn't invoked. This is true whether the search is performed from a full post or via ajax. Handling it this way keeps the actions cleaner, I think as you don't need to handle the search data in the other actions.
If you absolutely need to have the search parameters included, you could consider having the second form post via javascript, pick up the search field values dynamically and add them to the second form (as hidden fields) prior to posting the second form. You wouldn't have to maintain the values in two places in synchronization, but you would have to copy them to the second form before posting.
At the moment i got it like this:
Forms which has search box, posts query (and additional data if needed) to search controller which then renders search view. Search view is made from search box and search results partial views. During this - search box form is reconstructed by posted data.
If i need search results form to perform another search request (for example, with specified page index), it goes through ajax, which posts search box form + page index from search results form. Take a look here for ideas (update that JS method with targetId parameter for updating specified div/form and post additional data if needed here like this:
form.serialize()+"&pageIndex=5"
In short: if you need to maintain state of form + update another in one page - consider using partial updates, otherwise you will end up inventing ViewState 2.0.
One caveat with this way - it's tricky to make search box contain something what is related with search results (i.e. - total count of found items). Before i managed to handle this, our designer did that - i just need to add div with appropriate class name ("sbsubst" or something) and it looks that it's inside search box. :)
When you have few forms at your page each form sends only its own data. In WebForms you had only one form (at least server-side) and each control was included into this form. In ASP.NET MVC you can use the same scenario and I'm afraid you will have to if you want to have the described behavior. Don't forget - partial forms don't have to be real forms. Moreover, RenderPartial is mostly used for "control-like" layout creation.
As for the second part of your question I would suggest naming your text boxes in search form with some normal prefix like "search" or something like that. For instance, if you have text box "text" and "language" in the form, you will have "searchText" and "searchLanguage". These names are quite unique and you will have normal names in your parameters.
I am not suggesting you populating the hidden values in your results form on POST event since you said it's not an option for you but still it may be the only way if you want to have two forms.
I think the best approach will be storing the text from search input when it changes in the query part of your second form action url. For example (not tested):
$('input#yourSearchInput').change(function()
{
var searchText = $(this).val();
// or? var searchText = encodeURIComponent($(this).val());
var secondForm = $('form#secondFormId');
var action = secondForm.attr('action');
var queryStart = action.lastIndexOf('?search=');
if(queryStart > -1) {
action = action.substring(1, queryStart);
}
action = action + "?search=" + searchText;
secondForm.attr('action', action);
});
In Controller (or custom filter):
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var search = Request.QueryString["search"];
if(!String.IsNullOrEmpty(search)) {
ViewData["SearchFromPOST"] = search;
}
base.OnActionExecuting(filterContext);
}
In your Search Control:
<%= TextBox("yourSearchInputId", ViewData["SearchFromPOST"]) %>

Resources