动态创建DropDownList值作为Javascript数组的键

时间:2012-06-06 23:53:35

标签: javascript asp.net

我使用ASP.NET将REST请求发送到我无法控制的服务器。一种类型的请求是针对特定产品。该产品可以有许多不同的版本。一些变化可能是尺寸,颜色,金属(金,银等)。在一些产品的情况下,可能有一年变化和一个制造(福特,道奇等)。这里的要点是变化很多,有时只有一个变化,而其他时候产品可能有3或4个变化。

此外,还没有设置变体可能包含的选择项的列表。例如,一种产品可能有粉红色,绿色,蓝色的颜色变化,而另一种产品可能只有黑色或白色。尺码有时可以包含8,10,12和14个珠宝物品,或者小号,中号,大号可以包含一件衣物。

产品的变体组合始终在REST响应中返回。例如,我总是会知道产品变体属性,例如“颜色”,“尺寸”等等。我发现提供这些变体选项的最简洁方法是通过使用DropDownLists。我可以动态创建一个DropDownList' Color'并用粉红色,绿色和红色的选项填充它 - 或者其他任何东西。

粉红色和小号的产品与粉红色和大号的产品ID不同。

因此,如果网络访问者查找产品然后选择所需的变体,我需要客户端脚本逻辑,它将关联产品ID(基于所选的变体),以便将产品添加到他的购物车中。

REST响应包含一系列与变体组合相关联的产品ID。

我很抱歉这么冗长的解释,但我现在还没有任何代码可以提供。

我想知道的是,由于JavaScript不支持多维数组,因此我必须使用哪些选项来使用客户端Javascript逻辑来根据所选的值确定产品ID或者更多DropDownLists?

服务器端,无论是在我的XSLT模板中还是在ASP.NET代码隐藏中,我都可以使用" Page.ClientScript.RegisterArrayDeclaration"以某种方式,但我真的需要一些对特定变体名称无知的逻辑。

所以,例如,我有一个名为" WIDGET"并且它具有以下变体(布置为ProductID,variation1,variation2):

"00001", "Black", "Small"
"00002", "Pink", "Small"
"00003", "Red", "Small"
"00004", "Black", "Medium"
"00005", "Pink", "Medium"
"00006", "Red", "Medium"
"00007", "Black", "Large"
"00008", "Pink", "Large"
"00009", "Red", "Large"

我有2个DropDownLists:

颜色:黑色,粉红色,红色

尺寸:小,中,大

如何根据所选的variation1和variation2的值确定ProductID?请记住,这些属性是动态创建/填充的。客户端Javascript需要是通用的。我可能需要为Javascript逻辑创建几个数组。

通过可能的变化:

Page.ClientScript.RegisterArrayDeclaration("product_variation", "Color")
Page.ClientScript.RegisterArrayDeclaration("product_variation", "Size")

另外,如上所述,包含ProductID及其相关变体:

Page.ClientScript.RegisterArrayDeclaration("product_1_ID", "00001")
Page.ClientScript.RegisterArrayDeclaration("product_1_Color", "Black")
Page.ClientScript.RegisterArrayDeclaration("product_1_Size", "Small")

Page.ClientScript.RegisterArrayDeclaration("product_2_ID", "00002")
Page.ClientScript.RegisterArrayDeclaration("product_2_Color", "Black")
Page.ClientScript.RegisterArrayDeclaration("product_2_Size", "Medium")

等。但说实话,我不知道Javascript,我只是不知道如何在不看示例的情况下解决这个问题。我已经搜索过,但是找不到任何东西。我还可以在asp页面中创建一些隐藏的输入,如果它有助于客户端脚本。

有人能指出一个例子来帮我解决这个问题吗?是否有更简单/更合适的方式来做我需要的事情?

感谢您阅读所有这些内容。我几乎没有发布它,因为它太长了......

修改

以下gilly3提交的想法是正确的,我认为这应该如何运作。同样,我对任何风格的Javascript都有非常有限的经验,但是我尽可能地遵循了说明。我在某个地方遇到了问题,所以我想显示我的进度并询问你是否看错了。

在Product.aspx中,我创建了一个隐藏字段,其中包含正在查看的产品的变体:

<input id="hfdatalist" type="hidden" value="[
{"Id": "00001","Color": "Tidal", "Size": "2"},
{"Id": "00002","Color": "Tidal", "Size": "4"},
{"Id": "00003","Color": "Tidal", "Size": "6"}, 
{"Id": "00004","Color": "Tidal", "Size": "8"}, 
{"Id": "00005","Color": "Tidal", "Size": "10"}, 
{"Id": "00006","Color": "Tidal", "Size": "12"}, 
{"Id": "00007","Color": "Tidal", "Size": "14"}, 
{"Id": "00008","Color": "Tidal", "Size": "16"}
]" />

包含变体属性(颜色和大小)的隐藏字段:

<input id="hfpropctlmap" type="hidden" value=
"{"ddSize": "Size", "ddColor": "Color"}"
/>

我有两个下拉列表。一个用于ID为ddSize,另一个用于ID为ddColor的Color。 ddColor(在这种情况下)只有一个选项,&#34; Tidal&#34;。 ddSize有多个选项,2,4,6,8,10,12,14和16.单击这些下拉列表中的任何一个选项都将触发以下Javascript。

在Product.aspx中,我包含了gilly3提供的Javascript示例。我对一些代码的放置做了一些假设,但在大多数情况下我已经逐字地使用了它:

<!-- Augment JS files -->
<script type="text/JavaScript" src="../Scripts/augment.min.js"></script>

<!-- Variations Support Script -->
<script type="text/JavaScript">
    $("select").change(function () {

        var data = $.parseJSON($("#[id*='hfdatalist']").val());
        var propertyControlMap = $.parseJSON($("#[id*='hfpropctlmap']").val());
        var filteredData = data;

        var selections = $("select").map(function () {
            return {
                Property: propertyControlMap[this.id],
                Value: $(this).val()
            };
        }).get();

        filteredData = data.filter(function (item) {
            return selections.every(function (selection) {
                return item[selection.Property] == selection.Value;
            });
        });
        var selectedId = filteredData.length == 1 ? filteredData[0].Id : "";
        $("#[id*='SelectedVariationASIN']").val(selectedId)
    }); 
</script>

我知道这个代码有点乱,因为我有一些调试帮助。有2个警报显示保存到变量test和test1的隐藏字段的内容。这两个都完美地显示了隐藏字段的值(我想!)。

我设置断点并查看数据变量的内容。数组有8个元素(0-7),每个元素都包含正确的Id,Color和Size值。属性名称正确显示,实际数据有效。

与propertyControlMap相同。当我查看其数据时,属性名称和值是正确的。有2个元素(0-1)。

当然,filteredData也是正确的,因为此时它只是数据var的副本。

我看下一个var是选择。这是第一个迹象表明事情并不恰当。分配选择并查看其值后,我可以看到有9种方法和2种元素(0-1)。在查看元素时,选择[0] .Property是未定义的&#39;它的价值不正确&#39; 1036682&#39;。我认识到存储在名为&#34; hfSearchIndex&#34;的页面上另一个隐藏字段中的值的值。我不知道为什么会这样。该字段根本没有在脚本中引用。它与我的程序逻辑的这一部分无关。

奇怪的是,选择[1] .Property也包含&#39; undefined&#39;尽管Value包含我在ddSize下拉列表中点击的任何尺寸的实际值。所以,它是部分正确的。

从这一点来看,代码是不可预测的,可能不值得评论,除非说最后一行代码selectedId返回&#39;&#39;。

3 gilly3或其他任何人,你能看出我做错了吗?

编辑#2

gilly3提到propertyControlMap可能不包含下拉列表控件的正确ID。我不是肯定的,但我认为它确实包含正确的ID。但是,有一个Master Page,还有一个asp:PlaceHolder控件。所以Name属性确实会有一些错误。

以下是一些事实:

  1. hfdatalist看起来很完美(如上所示)。
  2. hfpropctlmap看起来很完美(如上所示)。
  3. var数据被正确初始化。数组的每个元素都包含hfdatalist隐藏字段中指定的完美ID,颜色和大小值。 (即:00001,黑色,小)。
  4. var propertyControlMap正确初始化。数组的每个元素都包含完美的下拉列表ID和正确的变体名称。 (即:ddColor和Color)。
  5. 问题的第一个迹象是Javascript中的var selections =。执行此行代码后,selections不包含有效数据。而不是选择等于:ID = 00001,颜色=黑色,大小=小它等于undefined = 1036682,颜色=黑色,大小=小。出于某种原因,ProductID未正确设置。
  6. 在呈现页面之后,我查看了源代码,这里是下拉列表:

    <select name="ctl00$PageContent$ddSize" id="ddSize">
        <option value="Small">Small</option>
        <option value="Medium">Medium</option>
    </select>
    
    <select name="ctl00$PageContent$ddColor" id="ddColor">
        <option value="Black">Black</option>
        <option value="Cobalt">Cobalt</option>
        <option value="Coral">Coral</option>
        <option value="Jade">Jade</option>
        <option value="Yellow">Yellow</option>
    </select>
    

    在页面的下方,还有另一个隐藏字段与此问题/答案中讨论的逻辑完全无关:

    <input type="hidden" name="SearchIndex" value="1036682">
    

    我无法弄清楚为什么在var selections

    的ProductID值中使用此字段的值(&#34; 1036682&#34;)

    我不确定如何进一步记录我的问题。我怀疑,就像gilly3一样,虽然propertyControlMap在其所有元素/属性中都包含完全有效/正确的数据,但我引用控件ID的方式有些不正确。

    如果由于Master Page和PlaceHolder导致控件ID出现问题,我该如何解决这个问题?

    注意:使用XSLT在XSLT转换中创建下拉列表控件在收到的REST响应上运行样式表。使用反序列化的REST响应在页面代码隐藏中创建隐藏字段。

    感谢您帮助我了解这个gilly3。由于我不了解Javascript,我真的陷入了困境。在这种情况下,我必须使用Javascript与跨浏览器兼容。让我有点紧张,在我的项目中包含我真的不太了解的代码,但我会特别注意它。

    希望我不要混淆。 :S

1 个答案:

答案 0 :(得分:1)

将数据作为对象数组存储在JavaScript中。如果您有List<T>强类型对象,则可以使用new JavaScriptSerializer().Serialize(myList);将其序列化为JSON。但是,听起来您手动解析XML,因此您可能还需要手动创建JSON。无论如何,你最终会得到一个格式如下的字符串:

[{
    "Id": "00001",
    "Color": "Black",
    "Size": "Small"
},
{
    "Id": "00002",
    "Color": "Pink",
    "Size": "Small"
},
...
{
    "Id": "00009",
    "Color": "Red",
    "Size": "Large"
}]

您需要一种方法将对象属性名称映射到相应的下拉列表。我会用JSON表达它:

{
    "<Color DropDownList.ClientID Goes Here>": "Color",
    "<Size DropDownList.ClientID Goes Here>": "Size",
    ... // etc
}

将这些JSON字符串删除到页面上的隐藏字段中。在JavaScript中,您将使用以下内容对其进行反序列化:

var data = $.parseJSON($("#<%= DataList.ClientID %>").val());
var propertyControlMap = $.parseJSON($("#<%= PropCtrlMap.ClientID %>").val());
var filteredData = data;

然后将onchange处理程序附加到下拉列表中,以便在选择更改时过滤数据。您需要创建一个属性名称数组和当前选定的值来测试您的数据。然后,您可以使用Array.filter()将数据减少到满足函数指定条件的项目。您可以在过滤器功能中使用Array.every()来测试每个项目,看它是否与所有选项匹配。 编辑然后将所选项目的ID填入隐藏字段,以便您可以通过按钮的点击处理程序在服务器上访问它:

$("select").change(function () {
    var selections = $("select").map(function () {
        return {
            Property: propertyControlMap[this.id],
            Value: $(this).val()
        };
    }).get();
    filteredData = data.filter(function(item) {
        return selections.every(function(selection) {
            return item[selection.Property] == selection.Value;
        });
    });
    var selectedId = filteredData.length == 1 ? filteredData[0].Id : "";
    $("#<%= SelectedItemId.ClientID %>").val(selectedId)
});

如果您想支持IE8或更早版本,请务必添加对Array.filter()Array.every()的支持,因为在IE9之前不支持这些内容。

编辑:如何访问服务器上的ID:

void AddToCartButton_Click(object sender, EventArgs e)
{
    ShoppingCart.AddToCart(SelectedItemId.Value);
}

但是,如果没有JavaScript,你也不能这样做吗?您可以使用所选值在单击处理程序中过滤服务器上的项目。下面是一个简化 - 你需要迭代下拉列表,而不是硬编码 - 但它说明了我的思路。

void AddToCartButton_Click(object sender, EventArgs e)
{
    string itemsXml = RestUtility.RequestItems();
    XDocument xItemsDoc = new XDocument(itemsXml);
    IEnumerable<XElement> xItems = xItemsDoc.Descendants("Item");
    XElement xSelected = xItems.SingleOrDefault(e =>
        e.Attribute("Color").Value == ColorSelector.SelectedValue &&
        e.Attribute("Size").Value == SizeSelector.SelectedValue);
    if (xSelected != null)
    {
        ShoppingCart.AddToCart(xSelected.Attribute("Id").Value);
    }
}