Moving items from one ListBox to another and getting items in ListBox

4.1k views Asked by At

I have an ASP.NET Wizard control. On my second step, I have two ListBoxes; the first ListBox item is populated from the server when the page loads.

The user then selects data from ListBox1 and moves it to ListBox2. Then, the user clicks on the NEXT button of the wizard. Somehow when the user clicks on next, the ListBox2 is empty.

I use jQuery to move data from ListBox1 to ListBox2.

<td class="style9">
                <asp:ListBox ID="registerCompCats" runat="server" CssClass="ListBox1"
                ClientIDMode="Static" DataTextField="value" DataValueField="key"
                Rows="5" size="5" style="width:135px; size:5px;" SelectionMode="Multiple" ></asp:ListBox>
                    &nbsp;&nbsp;&nbsp;</td>
                <td class="style1">
                    <table>
                        <tr>
                            <td style="padding-left: 20px;">
                                <img id="addCat" onclick="return addCat_onclick()" 
                        src="images/buttons/btn_addCat.jpg" title="Add Category" />
                            </td>
                        </tr>
                        <tr>
                            <td style="padding-left: 20px;">
                                <img id="removeCat" 
                        src="images/buttons/btn_removeCat.jpg" title="Remove Category" />
                            </td>
                        </tr>
                    </table>
                </td>
                <td>
                <asp:ListBox ID="registerCompAcats" runat="server" CssClass="ListBox2"
                ClientIDMode="Static" DataTextField="value" DataValueField="key"
                Rows="5" size="5" style="width:135px; size:5px; margin-top: 0px;" SelectionMode="Multiple" ></asp:ListBox>
                    &nbsp;<asp:RequiredFieldValidator ID="registerCompAcatsValidator" runat="server" 
                        ControlToValidate="registerCompAcats" Display="None" ErrorMessage="categories"></asp:RequiredFieldValidator></td>
1

There are 1 answers

0
Brandon Montgomery On BEST ANSWER

Event Validation

If you screw with list boxes and/or drop down lists' available options client-side (i.e. with jQuery or otherwise), the built-in ASP .NET form validation (referred to as "event validation") will kick in and throw an exception because you're submitting the form with different options than you gave it when it rendered the control in the first place. To get around this, you have to do this at the top of your .aspx page:

<%@ Page EnableEventValidation="false" %>

Keep in mind that if you do this, you'll need to perform form validation on dropdowns and listboxes yourself.

Viewstate

Every time the page is posted back to the server, these controls have 0 choices. Yes, you see the choices in the HTML, but on the server, they start out as having 0 choices. If you've enabled viewstate on these controls, then the choices which were present in the previous page render will be added by the ASP .NET framework automatically during the page lifecycle. This means that since the registerCompAcats control didn't have choices in the first page render, when the page is posted back to the server, it will still not have any choices.

These asp:ListBox controls render as <select> elements in the HTML. The way these work is that they post to the server just the values which were selected in these list boxes. This means that no matter what the choices are, you will only know about the items the user has selected in these list boxes in the form post.

Possible Solutions

There are several approaches to solving this problem. I will outline a couple.

Approach 1: Postback to add items to other listbox

This is probably the simplest, but least efficient. Every time the user clicks the "Add Category" button, you could have that cause a page postback rather than using jQuery to move the item from one listbox to the other. This allows the server-side code to control which choices are in each box, and viewstate works in your favor. You can also re-enable event validation on the page, which is generally a good idea.

<asp:ListBox id="lb1" runat="server" />
<asp:Button id="btnAdd" runat="server" />
<asp:ListBox id="lb2" runat="server" />

For the btnAdd.Click event:

Sub btnAdd_Click(sender As Object, args As EventArgs) Handles btnAdd.Click

  lb2.Items.AddRange(lb1.Items.Where(Function(i) i.Selected).ToArray())

End Sub

Approach 2: Use jQuery to add items; manipulate the post before submitting it

You'll need to have event validation turned off for this like I explained above. Use jQuery to move the items from one list to another - that's fine. However, before you actually cause a postback on the page, you'll use jQuery to collect all the values in the second listbox and put those values in a hidden field which is runat="server".

<asp:ListBox id="lb1" runat="server" />
<input type="button" value="Add" onclick="addCategory();" />
<asp:ListBox id="lb2" runat="server" />
<input type="hidden" id="hdnSelectedCategories" runat="server" />
<asp:Button id="btnSubmit" runat="server" onclientclick="preSubmit();" />

The jQuery portion:

<script type="text/javascript">

  var lb1, lb2, hdnSelectedCategories;

  $(function() {
    lb1 = $('#<%=lb1.ClientID %>');
    lb2 = $('#<%=lb2.ClientID %>');
    hdnSelectedCategories = $('#<%=hdnSelectedCategories.ClientID %>');
  });

  function addCategory() {
    lb2.append(lb1.find('option:selected'));
  }

  function preSubmit() {
    // collect all the values from the lb2 listbox into an array
    var values = [];
    lb2.find('option').each(function(index, item) {
      values.push($(item).val());
    });
    // now put the contents of the array in the hidden input, separated by commas
    hdnSelectedCategories.val(values.join(','));
  }
</script>

Now in your code behind, for the btnSubmit.Click event:

Sub btnSubmit_Click(sender As Object, args As EventArgs) Handles btnSubmit.Click

  Dim values As String() = hdnSelectedCategories.Value.Split(",")

  'TODO: Profit'

End Sub

In this approach, you'll also probably want to turn Viewstate off on the listboxes, as it adds bloat to the requests, and will reset your listboxes after the user clicks the "submit" button.

Disclaimer

I tested this code very minimally - it's just off the top of my head. But hopefully the explanation of event validation, viewstate, and the postback page lifecycle will help you understand what's actually going on, and you can come up with a solution that works for your situation.