0

我正在使用 ASP.NET 将 REST 请求发送到我无法控制的服务器。一种类型的请求是针对特定产品的。该产品可能有许多不同的变体。一些变化可能是尺寸、颜色、金属(金、银等)。对于某些产品,可能存在年份变化和品牌(福特、道奇等)。这里的重点是变化很多,有时只有一个变化,而有时一个产品可能有 3 或 4 个变化。

此外,没有关于变体可能包含多少选择的设置列表。例如,一种产品可能有粉色、绿色、蓝色的颜色变化,而另一种产品可能只有黑色或白色。尺寸有时可能包含 8、10、12 和 14 用于珠宝物品,或小、中、大用于服装。

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

颜色为粉红色且尺寸为小的产品与粉红色和大尺寸的产品具有不同的产品 ID。

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

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

对于这么长的解释,我感到很抱歉,但我目前没有任何代码可以展示。

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

在服务器端,无论是在我的 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 个下拉列表:

颜色:黑色、粉色、红色

尺寸:小号、中号、大号

如何根据选择的变量 1 和变量 2 的值确定 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。ddColor(在这种情况下)只有一个选项,“潮汐”。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 的副本。

我看的下一个变量是选择。这是事情不太对劲的第一个迹象。分配选择并查看其值后,我可以看到有 9 个方法和 2 个元素 (0-1)。查看元素后,selections[0].Property 为“未定义”,其值不正确“1036682”。我从存储在页面上另一个名为“hfSearchIndex”的隐藏字段中的值中识别出该值。我不知道为什么会这样。脚本中根本没有引用此字段。它与我的这部分程序逻辑无关。

奇怪的是,selections[1].Property 还包含“未定义”,尽管 Value 包含我在 ddSize 下拉列表中单击的任何大小的实际值。所以,它是部分正确的。

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

gilly3 或其他任何人,你能看到我做错了什么吗?

编辑#2

gilly3 提到 propertyControlMap 可能不包含下拉列表控件的正确 ID。我不肯定,但我认为它确实包含正确的 ID。但是,涉及到一个母版页和一个 asp:PlaceHolder 控件。所以 Name 属性确实有一些修改。

以下是一些事实:

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

页面呈现后,我查看源代码,这里是下拉列表:

<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">

我无法弄清楚为什么这个字段的值(“1036682”)被用于 ProductID 值var selections

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

如果这是由于母版页和占位符导致的控件 ID 问题,我该如何解决?

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

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

希望我没有混淆。:S

4

1 回答 1

1

将您的数据作为对象数组存储在 JavaScript 中。如果你有一个List<T>强类型对象,你可以使用new JavaScriptSerializer().Serialize(myList);. 但是,听起来您正在手动解析 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);
    }
}
于 2012-06-07T00:43:57.277 回答