开发者

ASP.NET MVC - Populating a form dynamically through the database

I am porting a search application from Classic ASP to ASP.NET MVC2. One of hte pages is a dynamically populated search form that is broken up into 4 categories, each with 2 rows.

The client is able to uncheck opti开发者_StackOverflowons for each of these categories. When this happens, each category is dynamically repopulated top to bottom, left to right. The person who programmed the Classic ASP version setup a subroutine that searched through the database (which has a boolean field for each search field) and then returned an array. He then took the array and called another subroutine that looped through the array and then generated each of the categories.

Right now, the only thing I can think of is to create a model that has methods for each of the categories, each of which return a List. A simple example would be:

class SearchPageOrganizer {

    // Declare SearchFields object
    private SearchFields fields;

    // Contructor; instantiates SearchFields object
    public SearchPageOrganizer(SearchFields searchFields) {
       this.fields =  searchFields;
    }

    // Gets a list of fields active in the characteristics category
    public List<String> GetCharactersticsList() {
        List<String> list = new List<String>();

        // Check if the Color field is active
        if (fields.Color) {
            list.Add("Color");
        }

        // Check if the Size field is active
        if (fields.Size) {
            list.Add("Size");
        }

        // Return the list
        return list;
    }
}

Then what I could do is split the list according to the size of each row, and then loop through each the list and call a user control that is able to render the HTML dynamically based on a name parameter.

The problem with this technique is that, for some odd reason, it feels like I am not doing this in the most simplistic way. For anyone who reads this, is there an easier way in which you would implement this?

Thanks!


This is something I've been wanting to investigate for sometime. Having dabbled in Rails, I got spoiled with the view binding to the model.

It seems that there is a helper in the MVC space called Html.EditorForModel(). This helper generates a form for the model to which the view is bound. I'm not exactly sure what it would do in your situation, but it certainly would be interesting to see the output and perhaps it might give you some ideas for a personal implementation.

Good luck!


Here is what I would recommend. Create a div that contains the dynamic content and put that content in a partial view. In this case there would be a partial view called Products.ascx

 <div id="ProductsContent">
    <% Html.RenderPartial("Products"); %>
 </div>

Call a javascript function when a category checkbox is clicked.

<input id="Category_1" type="checkbox" onclick="CategoryCheckChanged(1)" />
<input id="Category_2" type="checkbox" onclick="CategoryCheckChanged(2)" />
<input id="Category_3" type="checkbox" onclick="CategoryCheckChanged(3)" />

use JQuery to detect the value of the checkbox, then post to the server. In the example below my controller name is called Products. The information returned from the server is the updated partial view, which replaces the div contents.

function CheckChanged(id) 
{
    var bChecked = $("#Category_"+id).attr("checked");

    var value = 0;
    if(bChecked) value=1;

     $.post('<%= Url.Action("CategoryChanged","Products") %>'
        , { value: value, categoryid: id }
        , function(data) {
           if (data.success) {
              alert("Sweet !")
              //update the div with the new content
              $('#ProductsContent').html(data.newcontent);
           }
           else {
              alert("Bummer:" + data.msg);
           }

        }, "json");

}

Here is the CategoryChanged function in ProductsController

  [HttpPost]
  public ActionResult CategoryChanged(int value, int id)
  {
     try
     {
        //Save the change to the database
        SaveChangedCategoryValueToDatabase(id,value);

        //Create your View Model
        MyProductsViewModel vm = new MyProductsViewModel();

        return Json(new { success = true, newcontent =
           MyViewHelper.RenderPartialToString(this.ControllerContext, 
           "~/Views/Products/Products.ascx", 
           new ViewDataDictionary(vm), new TempDataDictionary()) });

     }
     catch(SystemException ex)
     {
         return Json(new { success = false, msg = ex.Message });
     }

  }

and finally... The helper function that takes renders a partial view to a string.

public static class MyViewHelper
{
  public static string RenderPartialToString(ControllerContext context
     , string partialViewName
     , ViewDataDictionary viewData
     , TempDataDictionary tempData)
  {
     ViewEngineResult result = 
        ViewEngines.Engines.FindPartialView(context, partialViewName);

     if (result.View != null)
     {
        StringBuilder sb = new StringBuilder();
        using (StringWriter sw = new StringWriter(sb))
        {
           using (HtmlTextWriter output = new HtmlTextWriter(sw))
           {
              ViewContext viewContext = new ViewContext(
                 context, result.View, viewData, tempData, output);
              result.View.Render(viewContext, output);
           }
        }

        return sb.ToString();
     }

     return String.Empty;
  }
}


How about adding the lists using JavaScript (jQuery) on the client-side when required? The data can be populated using an Ajax call. Once all fields have bee nfilled and the user submits, the action method can take all incoming parameters and perform a search based on that.


I recommend using the built in Ajax forms with MVC 2. You can have partial controls that build based on the model passed to them. Your approach would be something like this, roughly:

First, the controller

public PartialViewResult MySearchControl()
{
    //initialize the model

    return new PartialView(model)
}

[HttpPost]
public PartialViewResult MySearchControl(MyModel model)
{
    //do work, repopulate the model

    return new PartialView(model)
}

Then, in the View, you would have something like this.

<% using (Ajax.BeginForm("MySearchControl", "MySearch",
   new { },
   new AjaxOptions() { 
       HttpMethod = "Post",
       InsertionMode = InsertionMode.Replace,
       UpdateTargetId = "searchFormWrapper",
       OnSuccess = "doMoreWork"
        }, new { }))
{ %>

<div id="searchFormWrapper">
    <% Html.RenderAction<MySearchController>(x => x.MySearchControl()); %>
</div>

<input type="submit" id="mySubmitButton" value="submit" />

<% } %>

<script type="text/javascript">
    function doMoreWork()
    {
        // do anything needed after content is updated here
    }
</script>

Now, if you need a checkbox to fire the submit, you can use a little jquery magic

<script type="text/javascript">
    $(function () {
        $('.checkBoxClassSelector').live('change', new function(){
             $('#mySubmitButton').click();
        });
    });
</script>

the live method in jquery will make sure that action is attached to all current and future instances of the class if you give it to all checkboxes in your partial view. They will cause the ajax form to post back, which will then return your partial view - rewritten based on the updated model, and replace the contents of the div.

The benefit of this over pure client side is that you can let MVC do its thing with your model and not have to worry about formatting or changing a bunch of javascript to change how anything looks or works. You just change your view and everything works automagically.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜