在多个列表之间移动选项

发布于 2024-08-26 10:57:37 字数 1075 浏览 4 评论 0原文

我们目前有一个具有标准多选功能的表单,“这里是可用选项,这里是选定的选项,这里是一些来回移动内容的按钮。”然而,客户现在不仅希望能够选择某些项目,还希望能够对它们进行分类。例如,给定一个书籍列表,他们不仅要选择自己拥有的书籍,还要选择自己读过的书籍、想要阅读的书籍以及听说过的书籍。 (所有示例都是虚构的。)值得庆幸的是,选定的项目一次只能属于一个类别。

我可以找到许多在列表框之间移动项目的示例,但没有一个在多个列表框之间移动项目的示例。为了增加复杂性,该表单需要有两组列表+类别,例如除了上述书籍之外还需要分类的电影列表。

编辑:现在实际上坐下来尝试编码非 javascripty 位,我需要修改我的问题,因为我意识到多个选择列表不会真正从“我如何向服务器通知所有这些可爱的新内容”中起作用信息”的立场。所以html代码现在是一个伪列表框,即一个无序列表(

    )显示在一个带有滚动条的框中,每个列表项(
  • ) code>)有一组五个单选按钮(未选择/拥有/阅读/喜欢/听说)。

我的任务仍然大致相同:如何获取这个列表并轻松对项目进行分类,以便用户一眼就能看出什么属于哪个类别。 (伪列表框具有一些与多选列表框相同的缺点,即如果列表足够长以滚动,则很难判断选择了什么。)理想的解决方案将是拖放类型的东西,但是此时即使按钮也可以了。

另一项修改(很好的修改)是客户修改了列表,因此最长的列表现在“仅”有 62 个项目(而不是之前的数百个项目)。这些类别仍然主要包含零个、一个或两个选定的项目,如果用户过于热心,可能还会包含更多。

就操作系统和其他内容而言,该网站采用经典的 asp 语言(别再偷笑了!),服务器端代码是 VBScript,到目前为止,我们通过几乎从不使用客户端脚本的简单权宜之计避免了各种 Javascript 库。目前,该客户的这一表格是一个很大的例外。给他们一英寸,他们想要一英里......

哦,我必须补充一点:我不擅长 Javascript,或者真的不擅长任何 C 语言。大括号给我带来荨麻疹。我真的非常非常喜欢一些我可以复制的东西粘贴到我的页面中,也许调整一些变量名称,然后再也不会看它。女孩可以有梦想,不是吗? :)

[删除现有代码,因为它基本上不相关。]

We currently have a form with the standard multi-select functionality of "here are the available options, here are the selected options, here are some buttons to move stuff back and forth." However, the client now wants the ability to not just select certain items, but to also categorize them. For example, given a list of books, they want to not just select the ones they own, but also the ones they've read, the ones they would like to read, and the ones they've heard about. (All examples fictional.) Thankfully, a selected item can only be in one category at a time.

I can find many examples of moving items between listboxes, but not a single one for moving items between multiple listboxes. To add to the complication, the form needs to have two sets of list+categories, e.g. a list of movies that need to be categorized in addition to the aforementioned books.

EDIT: Having now actually sat down to try to code the non-javascripty bits, I need to revise my question, because I realized that multiple select lists won't really work from the "how do I inform the server about all this lovely new information" standpoint. So the html code is now a pseudo-listbox, i.e. an unordered list (<ul>) displayed in a box with a scrollbar, and each list item (<li>) has a set of five radio buttons (unselected/own/read/like/heard).

My task is still roughly the same: how to take this one list and make it easy to categorize the items, in such a way that the user can tell at a glance what is in what category. (The pseudo-listbox has some of the same disadvantages as a multi-select listbox, namely it's hard to tell what's selected if the list is long enough to scroll.) The dream solution would be a drag-and-drop type thing, but at this point even buttons would be OK.

Another modification (a good one) is that the client has revised the lists, so the longest is now "only" 62 items long (instead of the many hundreds they had before). The categories will still mostly contain zero, one, or two selected items, possibly a couple more if the user was overzealous.

As far as OS and stuff, the site is in classic asp (quit snickering!), the server-side code is VBScript, and so far we've avoided the various Javascript libraries by the simple expedient of almost never using client-side scripting. This one form for this one client is currently the big exception. Give 'em an inch and they want a mile...

Oh, and I have to add: I suck at Javascript, or really at any C-descendant language. Curly braces give me hives. I'd really, really like something I can just copy & paste into my page, maybe tweak some variable names, and never look at it again. A girl can dream, can't she? :)

[existing code deleted because it's largely irrelevant.]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

如梦 2024-09-02 10:57:37

有趣的是,我也昨天在谷歌上搜索“在多个列表框之间移动项目”,然后弹出了你的问题。

我没有阅读您的整篇文章,所以我不确定是否可以提供帮助。
但这解决了我的问题。
我下载了这个解决方案。
然后进行以下更改...

  • 在 html 中添加一个额外的 hidenfield
    每个(额外)列表框。
  • 修改如下,即可
    比较我所做的更改...

//...

公共部分类 ErrorActions : System.Web.UI.Page
{
私有 XmlDocument _xmlDocument = new XmlDocument();
公共列表框来自列表框
{
得到
{
返回lstFrom;
}
}

    public ListBox AbortListBox
    {
        get
        {
            return lstToAbort;
        }
    }

    public ListBox ClearingListBox
    {
        get
        {
            return lstToClearing;
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        Page.ClientScript.RegisterClientScriptInclude("listboxjs", "/JavaScripts/listbox.js");

        if (!IsPostBack)
        {
            string movejs = "move('{0}','{1}','{2}')";
            string unselectjs = "unselect('{0}')";
            lstFrom.Attributes["onclick"] = String.Format(unselectjs, lstToAbort.ClientID);
            lstFrom.Attributes["onclick"] = String.Format(unselectjs, lstToClearing.ClientID);
            lstToAbort.Attributes["onclick"] = String.Format(unselectjs, lstFrom.ClientID);
            lstToAbort.Attributes["onclick"] = String.Format(unselectjs, lstToClearing.ClientID);
            lstToClearing.Attributes["onclick"] = String.Format(unselectjs, lstFrom.ClientID);
            lstToClearing.Attributes["onclick"] = String.Format(unselectjs, lstToAbort.ClientID);

            btnToAbort.Attributes["onclick"] = String.Format(movejs, lstFrom.ClientID, lstToAbort.ClientID, hdnDropdownsAbort.ClientID);
            btnFromAbort.Attributes["onclick"] = String.Format(movejs, lstToAbort.ClientID, lstFrom.ClientID, hdnDropdownsAbort.ClientID);

            btnToClearing.Attributes["onclick"] = String.Format(movejs, lstFrom.ClientID, lstToClearing.ClientID, hdnDropdownsClearing.ClientID);
            btnFromClearing.Attributes["onclick"] = String.Format(movejs, lstToClearing.ClientID, lstFrom.ClientID, hdnDropdownsClearing.ClientID);
        }
        else
        {
            //if (!(String.IsNullOrEmpty(hdnDropdowns.Value)))
            //{
            //    PopulateListBoxes();
            //}

            if (!(String.IsNullOrEmpty(hdnDropdownsAbort.Value)))
            {
                PopulateAbortListBox();
            }

            if (!(String.IsNullOrEmpty(hdnDropdownsClearing.Value)))
            {
                PopulateClearingListBox();
            }
        }
    }

    private void PopulateListBox(ListBox listBox)
    {
        listBox.Items.Clear();
        XmlNodeList nodes = _xmlDocument.SelectNodes("listboxes/" + listBox.ClientID + "/option");
        foreach (XmlNode node in nodes)
        {
            listBox.Items.Add(new ListItem(node["key"].InnerText, node["value"].InnerText));
        }
    }

    //private void PopulateListBoxes()
    //{
    //    _xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdownsAbort.Value));
    //    //PopulateListBox(lstFrom);
    //    PopulateListBox(lstToAbort);
    //    PopulateListBox(lstToClearing);
    //}

    private void PopulateAbortListBox()
    {
        _xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdownsAbort.Value));
        PopulateListBox(lstToAbort);
    }

    private void PopulateClearingListBox()
    {
        _xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdownsClearing.Value));
        PopulateListBox(lstToClearing);
    }

    protected void btnDoIt_Click(object sender, EventArgs e)
    {
        MissionErrorCodeDB db = new MissionErrorCodeDB();
        db.DeleteErrorCodeActions(ErrorAction.AbortMission);
        db.DeleteErrorCodeActions(ErrorAction.GoToClearingStation);

        foreach (ListItem item in lstToAbort.Items)
        {
            db.AddErrorCodeAction(Convert.ToInt32(item.Value), ErrorAction.AbortMission);
        }
        foreach (ListItem item in lstToClearing.Items)
        {
            db.AddErrorCodeAction(Convert.ToInt32(item.Value), ErrorAction.GoToClearingStation);
        }
    }

    protected override void OnPreRender(EventArgs e)
    {
        MissionErrorCodeDB db = new MissionErrorCodeDB();
        List<MissionErrorCode> aborts = db.GetAll(ErrorAction.AbortMission);
        List<MissionErrorCode> clearing = db.GetAll(ErrorAction.GoToClearingStation);
        List<MissionErrorCode> all = db.GetAll();

        all.RemoveAll(delegate(MissionErrorCode mec) 
                    {
                        foreach (MissionErrorCode item in aborts)
                        {
                            if( mec.ErrorCode == item.ErrorCode )
                                return true;

                        }
                        return false;
                    });
        all.RemoveAll(delegate(MissionErrorCode mec)
                    {
                        foreach (MissionErrorCode item in clearing)
                        {
                            if (mec.ErrorCode == item.ErrorCode)
                                return true;

                        }
                        return false;
                    });

        populateBoxFromDatabase(AbortListBox, aborts);
        populateBoxFromDatabase(ClearingListBox, clearing);
        populateBoxFromDatabase(FromListBox, all);

        base.OnPreRender(e);
    }

    private void populateBoxFromDatabase(ListBox listBox, List<MissionErrorCode> errorCodes)
    {
        string text;
        int textLength = 46;

        listBox.Items.Clear();
        foreach (MissionErrorCode item in errorCodes)
        {
            if (item.ErrorText.Length < textLength)
            {
                text = item.ErrorCode + "  - " + item.ErrorText;
            }
            else
            {
                text = item.ErrorCode + "  - " + item.ErrorText.Substring(0, textLength - 1) + "...";
            }
            listBox.Items.Add(new ListItem(text, item.ErrorCode.ToString()));
        }
    }

}

//...

Funny, I also, just yesterday googled "moving items between multiple listboxes" and your question pop up.

I didnt read your entire post so Im not sure if I can help out.
But this solved my problem.
I downloaded this solution.
And then made the following changes...

  • Add one extra hidenfield in the html
    per (extra) listbox.
  • Modified like below, you can
    compare what changes I made...

//...

public partial class ErrorActions : System.Web.UI.Page
{
private XmlDocument _xmlDocument = new XmlDocument();
public ListBox FromListBox
{
get
{
return lstFrom;
}
}

    public ListBox AbortListBox
    {
        get
        {
            return lstToAbort;
        }
    }

    public ListBox ClearingListBox
    {
        get
        {
            return lstToClearing;
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        Page.ClientScript.RegisterClientScriptInclude("listboxjs", "/JavaScripts/listbox.js");

        if (!IsPostBack)
        {
            string movejs = "move('{0}','{1}','{2}')";
            string unselectjs = "unselect('{0}')";
            lstFrom.Attributes["onclick"] = String.Format(unselectjs, lstToAbort.ClientID);
            lstFrom.Attributes["onclick"] = String.Format(unselectjs, lstToClearing.ClientID);
            lstToAbort.Attributes["onclick"] = String.Format(unselectjs, lstFrom.ClientID);
            lstToAbort.Attributes["onclick"] = String.Format(unselectjs, lstToClearing.ClientID);
            lstToClearing.Attributes["onclick"] = String.Format(unselectjs, lstFrom.ClientID);
            lstToClearing.Attributes["onclick"] = String.Format(unselectjs, lstToAbort.ClientID);

            btnToAbort.Attributes["onclick"] = String.Format(movejs, lstFrom.ClientID, lstToAbort.ClientID, hdnDropdownsAbort.ClientID);
            btnFromAbort.Attributes["onclick"] = String.Format(movejs, lstToAbort.ClientID, lstFrom.ClientID, hdnDropdownsAbort.ClientID);

            btnToClearing.Attributes["onclick"] = String.Format(movejs, lstFrom.ClientID, lstToClearing.ClientID, hdnDropdownsClearing.ClientID);
            btnFromClearing.Attributes["onclick"] = String.Format(movejs, lstToClearing.ClientID, lstFrom.ClientID, hdnDropdownsClearing.ClientID);
        }
        else
        {
            //if (!(String.IsNullOrEmpty(hdnDropdowns.Value)))
            //{
            //    PopulateListBoxes();
            //}

            if (!(String.IsNullOrEmpty(hdnDropdownsAbort.Value)))
            {
                PopulateAbortListBox();
            }

            if (!(String.IsNullOrEmpty(hdnDropdownsClearing.Value)))
            {
                PopulateClearingListBox();
            }
        }
    }

    private void PopulateListBox(ListBox listBox)
    {
        listBox.Items.Clear();
        XmlNodeList nodes = _xmlDocument.SelectNodes("listboxes/" + listBox.ClientID + "/option");
        foreach (XmlNode node in nodes)
        {
            listBox.Items.Add(new ListItem(node["key"].InnerText, node["value"].InnerText));
        }
    }

    //private void PopulateListBoxes()
    //{
    //    _xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdownsAbort.Value));
    //    //PopulateListBox(lstFrom);
    //    PopulateListBox(lstToAbort);
    //    PopulateListBox(lstToClearing);
    //}

    private void PopulateAbortListBox()
    {
        _xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdownsAbort.Value));
        PopulateListBox(lstToAbort);
    }

    private void PopulateClearingListBox()
    {
        _xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdownsClearing.Value));
        PopulateListBox(lstToClearing);
    }

    protected void btnDoIt_Click(object sender, EventArgs e)
    {
        MissionErrorCodeDB db = new MissionErrorCodeDB();
        db.DeleteErrorCodeActions(ErrorAction.AbortMission);
        db.DeleteErrorCodeActions(ErrorAction.GoToClearingStation);

        foreach (ListItem item in lstToAbort.Items)
        {
            db.AddErrorCodeAction(Convert.ToInt32(item.Value), ErrorAction.AbortMission);
        }
        foreach (ListItem item in lstToClearing.Items)
        {
            db.AddErrorCodeAction(Convert.ToInt32(item.Value), ErrorAction.GoToClearingStation);
        }
    }

    protected override void OnPreRender(EventArgs e)
    {
        MissionErrorCodeDB db = new MissionErrorCodeDB();
        List<MissionErrorCode> aborts = db.GetAll(ErrorAction.AbortMission);
        List<MissionErrorCode> clearing = db.GetAll(ErrorAction.GoToClearingStation);
        List<MissionErrorCode> all = db.GetAll();

        all.RemoveAll(delegate(MissionErrorCode mec) 
                    {
                        foreach (MissionErrorCode item in aborts)
                        {
                            if( mec.ErrorCode == item.ErrorCode )
                                return true;

                        }
                        return false;
                    });
        all.RemoveAll(delegate(MissionErrorCode mec)
                    {
                        foreach (MissionErrorCode item in clearing)
                        {
                            if (mec.ErrorCode == item.ErrorCode)
                                return true;

                        }
                        return false;
                    });

        populateBoxFromDatabase(AbortListBox, aborts);
        populateBoxFromDatabase(ClearingListBox, clearing);
        populateBoxFromDatabase(FromListBox, all);

        base.OnPreRender(e);
    }

    private void populateBoxFromDatabase(ListBox listBox, List<MissionErrorCode> errorCodes)
    {
        string text;
        int textLength = 46;

        listBox.Items.Clear();
        foreach (MissionErrorCode item in errorCodes)
        {
            if (item.ErrorText.Length < textLength)
            {
                text = item.ErrorCode + "  - " + item.ErrorText;
            }
            else
            {
                text = item.ErrorCode + "  - " + item.ErrorText.Substring(0, textLength - 1) + "...";
            }
            listBox.Items.Add(new ListItem(text, item.ErrorCode.ToString()));
        }
    }

}

//...

心病无药医 2024-09-02 10:57:37

为了避免大量的 Javascript,我建议您使用几个 Ajax 调用来完成这项工作,

  1. 在项目旁边添加几个按钮(已经有、想要等)。每个按钮都应该调用服务器中的一个页面,将项目设置为正确的类别。
  2. 在成功回调中,调用其他ajax函数,仅刷新受影响的类别列表。

使用 jQuery,您会发现进行调用非常简单。

祝你好运。

To avoid big chunks of Javascript I suggest you to do the work with a couple a Ajax calls

  1. Add several buttons next to the item (Already have it, Want it, etc). Each button should call a page in the server that sets the item to the correct category.
  2. In the success callback, call other ajax function that refresh only the category list affected.

Use jQuery and you will see that making the calls are pretty simple.

Good luck.

梦晓ヶ微光ヅ倾城 2024-09-02 10:57:37

好吧,似乎没有人愿意为我做我的工作,所以这就是我们最终所做的。 (它还没有完全完成;当它完成时,我可能会为了完整性而发布代码。)

我们已经冒险下载了 JQuery,特别是 JQuery UI“Sortable”函数。就像我说的,主下拉菜单现在是一个伪列表框,即具有限制高度和 overflow:autoul。每个项目旁边都有五个单选按钮,这些按钮用 Javascript 隐藏。 (也就是说,如果 Javascript 不可用,用户只会看到带有单选按钮的列表。)当您将项目从主列表拖到(脚本生成的)类别列表中时,相应的单选按钮会被标记。还会有一些在页面加载时运行的代码,将已标记的选项从主列表移动到适当的类别(即用于编辑功能)。

Well, nobody seems to want to do my work for me, so here's what we ended up doing. (It's not entirely done yet; when it is, I might post the code just for completeness' sake.)

We've taken the plunge and downloaded JQuery, specifically the JQuery UI "Sortable" functions. Like I said, the main dropdown is now a pseudo-listbox, i.e. a ul with restricted height and overflow:auto. Each item has five radio buttons next to it, which are hidden with Javascript. (That is, if Javascript isn't available, the user just sees a list with radio buttons.) When you drag items from the main list into the (script-generated) category lists, the appropriate radio button is marked. There will also be some code that runs on page load to move already-marked options from the main list to the appropriate category (i.e. for editing capability).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文