tags:

views:

441

answers:

4

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!

+1  A: 

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.

tvanfosson
Thanks for the input, I already thought of the javascript option, but am trying to stay away from relying on client side scripting. I think I am leaning towards your first option, though I am reluctant to rely on server side session state, I even thought about using the query string, but thats a lot to push around from page to page. I had also thought about base64 encoding the search control's form values and stuffing them in a hidden variable on the other form, maybe calling it ViewState...oh, wait, that's been done before...but seriously would that be too evil?
cnaegle
Man, don't be afraid of client side. It eases development a lot if used properly + makes user experience much better.
Arnis L.
After thinking it through and looking at the possible solutions, we decided to persist the search critera server side so I am marking your answer as correct. Thanks.
cnaegle
A: 

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"]) %>
eu-ge-ne
Thanks for the input and idea. However, we are dealing with banking clients that may or may not allow client side scripting so this would not be a good option for us.
cnaegle
A: 

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.

Alex Konduforov
I'm using the partial view to keep it DRY because the search form is on almost every page in the application. As stated above, I want to stay away from prefixing every field because it just seems cumbersome and wrong and the search model names won't match the underlying database schema. Is this being too picky on my part? Perhaps. Right now I am just exploring my options before I commit to an architecture and code myself into a corner. Thanks for the input
cnaegle
+1  A: 

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. :)

Arnis L.
"otherwise you will end up inventing ViewState 2.0" - totally agree :)
eu-ge-ne
Arnis L.