3

Okay - so I have been pulling out my hair on this one for far too long now. Hopefully you guys can help out.

I have a form that allows a user to input/edit data about their company. Most of it is pretty straight-forward form field editing, but I have one part where I am allowing the user to select what state(s) their business operates in and then assign a contact to that state. I am using jQuery and 2 listBox controls where I allow the user to double-click the state(s) they want to operate in. The jQuery moves the selected state over to the other listBox as well as to a dropdown control where they can then enter their state-specific contact information.

Now for the "hair pulling out" part. I have seen a lot of posts about taking the data from the 2nd listBox control, putting it into an array and placing it into a hidden form field - but the example of how to do this are few and far between. The few that I have found I have not successfully integrated. Any help there would by much appreciated.

The other piece of the puzzle is that this page is supposed to function as a page the user can edit as well - so on the initial load my page should (ideally) preload the state(s) a user has already selected via jQuery into the second listBox...but the states that go into the second listBox should NOT show up in the first. Ugh. Any pointers as to how to accomplish this would also be greatly appreciated.

Here is my code:

ASPX file:

<%@ Page Title="Mappings" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Mapping.aspx.cs" Inherits="Account_Mapping" EnableEventValidation="false" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
<script language="javascript" type="text/javascript">
    $(function () {
        var sourceState = $('#MainContent_sourceState option').clone();

        $('#stateAllA').click(function () {
            $('#MainContent_sourceState option').appendTo('#MainContent_targetState, #MainContent_contactState');
        });

        $('#stateAllR').click(function () {
            $('#MainContent_targetState option').appendTo('#MainContent_sourceState');
            $('#MainContent_contactState option').remove();
        });



        $('#MainContent_sourceState').dblclick(function () {
            $('#MainContent_sourceState option:selected').appendTo('#MainContent_targetState, #MainContent_contactState');
        });


        $('#MainContent_targetState').dblclick(function () {
            var targetList = $('#MainContent_targetState option:selected');
            var targetVal = $('#MainContent_targetState option:selected').val();
            targetList.appendTo('#MainContent_sourceState');
            $('#MainContent_contactState option[value=' + targetVal + ']').remove();
            //$('#contactState option:selected').remove();
            var foption = $('#MainContent_sourceState option:first');
            var soptions = $.makeArray($('#MainContent_sourceState option:not(:first)')).sort(function (a, b) {
                return a.text == b.text ? 0 : a.text < b.text ? -1 : 1
            });
            $('#MainContent_sourceState').html(soptions).prepend(foption);
            foption.attr("selected", true).siblings("option").removeAttr("selected");
        });

    });
</script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
        Admin
    </h2>
    <p>
    Please fill in all the required information and click "submit" when complete.
    </p>
    <div class="formLeft">
        <b>Company Name:</b>
    </div>
    <div class="formRight">
        <asp:TextBox ID="comp_Name" runat="server" CssClass="textEntry"></asp:TextBox>
    </div>
    <div class="formLeft">
        <b>Company Phone:</b>
    </div>
    <div class="formRight">
        <asp:TextBox ID="comp_Phone" runat="server" CssClass="textEntry"></asp:TextBox>
    </div>
    <div class="formLeft">
        <b>Main Contact Person:</b>
    </div>
    <div class="formRight">
        <asp:TextBox ID="comp_Contact" runat="server" CssClass="textEntry"></asp:TextBox>
    </div>
    <div class="formLeft">
        <b>Main Email Address:</b>
    </div>
    <div class="formRight">
        <asp:TextBox ID="comp_Email" runat="server" CssClass="textEntry"></asp:TextBox>
    </div>
    <div class="formLeft">
        <b>Company Website:</b>
    </div>
    <div class="formRight">
        <asp:TextBox ID="comp_Website" runat="server" CssClass="textEntry"></asp:TextBox>
    </div>
    <div class="formLeft">
        <b>Company Description:</b>
    </div>
    <div class="formRight">
        <asp:TextBox ID="comp_Desc" runat="server" CssClass="textAreaEntry" TextMode="MultiLine"></asp:TextBox>
    </div>
    <div class="formLeft">
        <b>Company Access:</b>
    </div>
    <div class="formRight">
        <asp:TextBox ID="comp_Access" runat="server" CssClass="textAreaEntry" TextMode="MultiLine"></asp:TextBox>
    </div>
    <hr />
    <p>
    <b>Which state(s) do you operate in?</b>
    </p>
    <div class="formLeft">
        <b>OPTIONS:</b> <a id="stateAllA" href="#" style="font-size:11px" onclick="return false;">(add all)</a><br />
        <em style="font-size:12px">(double-click an item to add it to your list)</em><br />
        <asp:ListBox ID="sourceState" runat="server" CssClass="selectEntry" SelectionMode="Multiple" DataSourceID="myDSID" DataTextField="state_name" DataValueField="state_ID"></asp:ListBox>
        <asp:SqlDataSource ID="myDSID" runat="server" 
            ConnectionString="<%$ ConnectionStrings:myDatasource %>" 
            SelectCommand="SELECT [state_ID], [state_name] FROM [states]">
        </asp:SqlDataSource>
    </div>
    <div class="formRight">
        <b>YOUR SELECTIONS:</b> <a id="stateAllR" href="#" style="font-size:11px" onclick="return false;">(remove all)</a><br />
        <em style="font-size:12px">(double-click an item to remove it from your list)</em><br />
        <asp:ListBox ID="targetState" runat="server" CssClass="selectEntry" SelectionMode="Multiple"></asp:ListBox>
        <asp:HiddenField ID="hdnStates" runat="server" />
    </div>
    <p>
    <b>Do you wish to assign state-specific contacts? If so, choose the appropriate state and fill out the info below.</b><br>
    </p>
    <p>
    <asp:DropDownList ID="contactState" runat="server"></asp:DropDownList>
    </p>
    <div align="right" style="margin-top:5px;">
        <asp:Button ID="Button1" runat="server" Text="Submit" 
            onclick="Button1_Click" />
    </div>
</asp:Content>

And my CodeBehind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Configuration;
using System.Data;
public partial class Account_Mapping : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //let's get our passed variables
        //the company you're editing comes from a dropdown on prev page
        string passedComp = Session["searchCompany"].ToString();

        if (!IsPostBack)
        {
            //now let's get all the relevant data from the DB

            //first, the easy stuff
            DataTable dt1 = GetBasicCompData(passedComp);

            //let's populate those fields in the form
            comp_Name.Text = dt1.Rows[0][0].ToString();
            comp_Phone.Text = dt1.Rows[0][1].ToString();
            comp_Contact.Text = dt1.Rows[0][2].ToString();
            comp_Email.Text = dt1.Rows[0][3].ToString();
            comp_Website.Text = dt1.Rows[0][4].ToString();
            comp_Desc.Text = dt1.Rows[0][5].ToString();
            comp_Access.Text = dt1.Rows[0][6].ToString();

            //state mapping
            DataTable dt2 = GetStateCompData(passedComp);

            for (int i = 0; i < dt2.Rows.Count; i++)
            {
                //targetState.DataSource = dt2;
                //targetState.DataValueField = "state_ID";
                //targetState.DataTextField = "state_Name";
                //targetState.DataBind();

                //contactState.DataSource = dt2;
                //contactState.DataValueField = "state_ID";
                //contactState.DataTextField = "state_Name";
                //contactState.DataBind();
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        //breakpoint here to try and return my values 
        string myStates = hdnStates.Value;
    }


    public DataTable GetBasicCompData(string strComp)
    {
        //Query DB based on result
        string strConn = ConfigurationManager.ConnectionStrings["myConn"].ConnectionString;
        SqlConnection con = new SqlConnection(strConn);
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = con;
        cmd.CommandType = System.Data.CommandType.Text;
        cmd.Parameters.AddWithValue("@Comp", strComp);
        cmd.CommandText = "SELECT companies.comp_Name, companies.comp_Phone, companies.comp_Contact, companies.comp_Email, companies.comp_Website, companies.comp_Desc, companies.comp_Access FROM companies WHERE comp_ID =  ''+ @Comp +''";
        DataSet objDs = new DataSet();
        SqlDataAdapter dAdapter = new SqlDataAdapter();
        dAdapter.SelectCommand = cmd;
        con.Open();
        dAdapter.Fill(objDs);
        con.Close();
        return objDs.Tables[0];
    }

    public DataTable GetStateCompData(string strComp)
    {
        //Query DB based on result
        string strConn = ConfigurationManager.ConnectionStrings["myConn"].ConnectionString;
        SqlConnection con = new SqlConnection(strConn);
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = con;
        cmd.CommandType = System.Data.CommandType.Text;
        cmd.Parameters.AddWithValue("@Comp", strComp);
        cmd.CommandText = "SELECT states.state_ID, states.state_Name, contact_Name, contact_Phone, contact_Email FROM states INNER JOIN companies_states ON states.state_ID = companies_states.state_ID WHERE comp_ID = ''+ @Comp +''";
        DataSet objDs = new DataSet();
        SqlDataAdapter dAdapter = new SqlDataAdapter();
        dAdapter.SelectCommand = cmd;
        con.Open();
        dAdapter.Fill(objDs);
        con.Close();
        return objDs.Tables[0];
    }
}

So there you have it. It's a lot to digest, I know. I'd love a kick in the right direction. :)

4

1 に答える 1

4

This is one way to do it, I am using:

This is a full working example, the output is:

enter image description here

As you can see, the viewstate is emulated on each post so you can have access in server code to both list items

This is the code:

ASPX

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="KnockoutJS1.aspx.cs" Inherits="WebApplication1.KnockoutJS1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
    <script type="text/javascript" src="Scripts/jquery-1.7.2.min.js"></script>
    <script type="text/javascript" src="Scripts/knockout-2.1.0.js"></script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <asp:HiddenField runat="server" ID="list1Values" />
    <asp:HiddenField runat="server" ID="list2Values" />
    <asp:ListBox Rows="10" Width="15%" runat="server" ID="list1" DataTextField="Name" DataValueField="ID">
    </asp:ListBox>
    <asp:ListBox Rows="10" Width="15%" runat="server" ID="list2" DataTextField="Name" DataValueField="ID">
    </asp:ListBox>
    <asp:Button Text="Save" runat="server" OnClick="saveData_Click" />
    <br /><asp:Label ID="lblMessage" runat="server" />
    <script type="text/javascript">
        function state(id, name) {
            return {
                ID: ko.observable(id),
                Name: ko.observable(name)
            };
        }
        $(function () {
            var options1 = ko.observableArray();
            var options2 = ko.observableArray();
            var list1ID = "<%= this.list1.ClientID%>";
            var list2ID = "<%= this.list2.ClientID%>";

            $("#" + list1ID).find("option").each(function () {
                options1.push(new state($(this).val(), $(this).text()));
            });
            $("#" + list2ID).find("option").each(function () {
                options2.push(new state($(this).val(), $(this).text()));
            });
            function serializeArrays(a1, a2) {
                var list1ValuesID = "<%= this.list1Values.ClientID %>";
                var list2ValuesID = "<%= this.list2Values.ClientID %>";

                $("#" + list1ValuesID).val(ko.toJSON(a1));
                $("#" + list2ValuesID).val(ko.toJSON(a2));
            }
            var viewModel = {
                states1: options1,
                states2: options2,
                states1Selected: ko.observable(),
                states2Selected: ko.observable(),
                execute1: function () {
                    this.states2.push(this.states1Selected());
                    this.states1.remove(this.states1Selected());
                    serializeArrays(this.states1(), this.states2());
                },
                execute2: function () {
                    this.states1.push(this.states2Selected());
                    this.states2.remove(this.states2Selected());
                    serializeArrays(this.states1(), this.states2());
                }
            };

            ko.applyBindings(viewModel);
        });
    </script>
</asp:Content>

Code behind

public partial class KnockoutJS1 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!this.IsPostBack)
        {
            this.list1.Attributes.Add("data-bind", "options: states1, optionsText: 'Name', value: states1Selected, event: { dblclick: execute1 }");
            this.list2.Attributes.Add("data-bind", "options: states2, optionsText: 'Name', value: states2Selected, event: { dblclick: execute2 }");

            var s = Builder<State>.CreateListOfSize(6).Build();

            this.list1.DataSource = s;
            this.list1.DataBind();
        }
        else
        {
            var states1 = JsonConvert.DeserializeObject<IEnumerable<State>>(this.list1Values.Value);
            var states2 = JsonConvert.DeserializeObject<IEnumerable<State>>(this.list2Values.Value);

            this.list1.DataSource = states1;
            this.list1.DataBind();
            this.list2.DataSource = states2;
            this.list2.DataBind();
        }
    }

    protected void saveData_Click(object sender, EventArgs e)
    {
        this.lblMessage.Text = string.Empty;

        var states1 = JsonConvert.DeserializeObject<IEnumerable<State>>(this.list1Values.Value);
        var states2 = JsonConvert.DeserializeObject<IEnumerable<State>>(this.list2Values.Value);

        foreach (var item in states1)
        {
            this.lblMessage.Text += "List1: " + item.Name + " " + item.ID.ToString() + "<br/>";
        }
        this.lblMessage.Text += "<br/><br/>";
        foreach (var item in states2)
        {
            this.lblMessage.Text += "List2: " + item.Name + " " + item.ID.ToString() + "<br/>";
        }
    }
}

public class State
{
    public int ID { get; set; }
    public string Name { get; set; }
}
于 2012-06-27T05:16:23.160 に答える