Developer forum

Forum » Ecommerce - Standard features » Add multiple products to context cart

Add multiple products to context cart

Bjørn Kamfjord
Reply

Hi. I need som help, I'm trying to add multiple products to a context cart using the multiform. But it is not working as expected. It adds the product to the regular cart in stead. Adding one product at a time works just fine. 

This works for a single product add to context cart.

                @foreach (var context in p.GetLoop("OrderContexts"))
                {
                    <form method="post" role="form">
                        <input type="hidden" name="ProductID" value="@productID" />

                        <input type="hidden" name="OrderContext" value="@context.GetValue("OrderContext.ID")" />
                        <button type="submit" class="btn btn-default pull-left" name="CartCmd" value="add">@Translate("Add to cart") (@context.GetValue("OrderContext.Name")) </button>
                    </form>

                }

This does not work. I'm trying to add multiple products at the same time. (the products are added to the "regular" cart though...)


@{
    var c = 1;
}

<form name="multiForm" id="multiForm" method="post">
    <input type="hidden" name="CartCmd" id="CartCmd" value="addMulti" />

    @foreach (LoopItem prod in GetLoop("Products"))
    {
        <input type="hidden" name="ProductLoopCounter@(c)" id="ProductLoopCounter@(c)" value="@(c)">
        <input type="hidden" name="ProductID@(c)" id="ProductID@(c)" value="@prod.GetString("Ecom:Product.ID")">
        <input type="hidden" name='Quantity@(c)' value='1' />
        foreach (var context in prod.GetLoop("OrderContexts"))
        {

            <input type="hidden" name="OrderContext@(c)" value="@context.GetValue("OrderContext.ID")" />

        }

        c++;
    }
    <button type="submit" class="btn btn-default pull-left" name="CartCmd" value="addMulti">@Translate("Add all to cart")</button>
</form>

Replies

 
Morten Bengtson Dynamicweb Employee
Morten Bengtson
Reply

Hi Bjørn,

In your "add multiple" example you have two "cartcmd" inputs:

<input type="hidden" name="CartCmd" id="CartCmd" value="addMulti" />
...
<button type="submit" class="btn btn-default pull-left" name="CartCmd" value="addMulti">@Translate("Add all to cart")</button>

Try to change this so that it only contains one input for "cartcmd".

And then try to use a single input for "OrderContext" like in your first example. I don't think you can specify different contexts for each of the products added to the cart using "addmulti".

Best regards,
Morten

 
Bjørn Kamfjord
Reply
<form name="multiForm" id="multiForm" method="post">
    @*<input type="hidden" name="CartCmd" id="CartCmd" value="addMulti" />*@
    
        @foreach (LoopItem prod in GetLoop("Products"))
        {
            <input type="hidden" name="ProductLoopCounter@(c)" id="ProductLoopCounter@(c)" value="@(c)">
            <input type="hidden" name="ProductID@(c)" id="ProductID@(c)" value="@prod.GetString("Ecom:Product.ID")">
            <input type="hidden" name='Quantity@(c)' value='1' />
            foreach (var context in prod.GetLoop("OrderContexts"))
            {
                <input type="hidden" name="OrderContext" value="@context.GetValue("OrderContext.ID")" />
            }
            c++;

        }

    <button type="submit" class="btn btn-default pull-left" name="CartCmd" value="addMulti">@Translate("Add all to cart")</button>
</form>

 

no luck.... :(

 

The order context is just one result...

 
Bjørn Kamfjord
Reply

The parsed result looks like this.

<form name="multiForm" id="multiForm" method="post">
            <input name="ProductLoopCounter1" id="ProductLoopCounter1" value="1" type="hidden">
            <input name="ProductID1" id="ProductID1" value="510100" type="hidden">
            <input name="Quantity1" value="1" type="hidden">
                <input name="OrderContext" value="CatalogGenerator" type="hidden">
            <input name="ProductLoopCounter2" id="ProductLoopCounter2" value="2" type="hidden">
            <input name="ProductID2" id="ProductID2" value="386521" type="hidden">
            <input name="Quantity2" value="1" type="hidden">
                <input name="OrderContext" value="CatalogGenerator" type="hidden">
    <button type="submit" class="btn btn-default pull-left" name="CartCmd" value="addMulti">Add all to cart</button>
</form>
 
Morten Bengtson Dynamicweb Employee
Morten Bengtson
Reply

There should only be one "OrderContext" input.

Here are some of the options you have...

A) Make sure that the form only contains a single "OrderContext" input (productCounter == 1)

<form method="post">
    <input name="cartcmd" value="addmulti" type="hidden" />
 
    @{
        var productCounter = 0;
        foreach (var product in GetLoop("Products"))
        {
            productCounter += 1;
 
            var productId = product.GetString("Ecom:Product.ID");
            var productVariantId = product.GetString("Ecom:Product.VariantID");
 
            if (productCounter == 1)
            {
                <select name="ordercontext">
                    <option value="">Default</option>
                    @foreach (var context in product.GetLoop("OrderContexts"))
                    {
                        var contextId = context.GetString("OrderContext.ID");
                        var contextName = context.GetString("OrderContext.Name");
                        var isCurrentContext = context.GetBoolean("OrderContext.IsCurrent");
                        <option value="@contextId" selected="@isCurrentContext">@contextName</option>
                    }
                </select>
            }
 
            <input type="hidden" name="ProductLoopCounter@(productCounter)" value="@(productCounter)" />
            <input type="hidden" name="ProductID@(productCounter)" value="@productId" />
            <input type="hidden" name="VariantID@(productCounter)" value="@productVariantId" />
            <input type="hidden" name="Quantity@(productCounter)" value="1" />
        }
    }
 
    <button type="submit">Add to cart</button>
</form>

B) Make a context selector in your page layout

<form method="post">
    <select name="setordercontext">
        <option value="">Default</option>
        @foreach (var context in GetLoop("OrderContexts"))
        {
            var contextId = context.GetString("OrderContext.ID");
            var contextName = context.GetString("OrderContext.Name");
            var isCurrentContext = context.GetBoolean("OrderContext.IsCurrent");
            <option value="@contextId" selected="@isCurrentContext">@contextName</option>
        }
    </select>
 
    <button type="submit">Select order context</button>
</form>

If you don't want to display the selector then you can either set the default cart context on the shop or get the id of context from a configuration setting or from an item setting, etc.

Instead of an input with name="OrderContext" you can use an input with name="SetOrderContext" which will store the selected context in a cookie and remember this choice when the user navigates to another page.


Best regards,
Morten

 
Bjørn Kamfjord
Reply

Hey. I thought I had solved this, but for some reason, my template doesn't work properly.

I can add products to the the cart, but the variants are not added? Also, if I add the same product variant twice it will be put on separat orderlines. ? Can you see what I'm doing wrong?

What happens is, I add product A, with variant 1.X and 1.Y, in the cart I now have Product A and Product A, (no variants). If I do the same again, I will have Product A, 4 times (separat orderlines) still no variants.

It's a fairly complex list of products.... 😵 I need to be able to display and add all the different variants at the same time.  The list is loaded and prossesed with Ajax.

Link to site, https://egwbp-apw-test.azurewebsites.net/preorder

@{
    int userID = int.Parse(GetGlobalValue("Global:Extranet.UserID"));
    int productListPageId = GetInteger("Ecom:ProductList:Page.ID");
    List<LoopItem> products = GetLoop("Products");
    int c = 1;


    int rowCounter = 1;
}

@RenderProductFiltersRow()

<div class="col-12">

    <hr class="my-2" />
    <div class="row">
        <form name="multiForm" id="PreorderMultiForm" method="post" action="/default.aspx?ID=@productListPageId">

            <input type="hidden" name="CartCmd" id="CartCmd" value="addMulti" />

            @foreach (LoopItem p in products)
            {

                var id = p.GetString("Ecom:Product.ID");

                var imageCustom = p.GetString("Product.ImageCustom");
                //var allowBuy = p.GetBoolean("Product.AllowBuy");
                var isInCart = p.GetBoolean("Ecom:Product.IsInCart");
                var languageID = p.GetString("Ecom:Product.LanguageID");

                var dbPrice = p.GetDouble("Ecom:Product.Price");
                var salesPrice = (dbPrice * 1.25);
                var stockNumber = p.GetDouble("Ecom:Product.Stock");
                var stockText = p.GetString("Ecom:Product:Stock.Text");
                var stockImage = p.GetValue("Ecom:Product:Stock.Image");
                var stock = (!string.IsNullOrEmpty(stockText)) ? string.Format("{0} {1}", stockText, stockImage) : string.Format("{0} stk.", stockNumber > 0 ? stockNumber : 0);

                var varComb = p.GetLoop("VariantCombinations");

                <div class="col-12  m_bottom_10 @(p.GetBoolean("Ecom:Product.IsInCart") ? "in_cart" : string.Empty)" data-productno="@p.GetString("Ecom:Product.Number")">
                    <div class="row p-2 m-0 p-2 pb-4 bg_color_white">

                        <div class="col-2">
                            <img class="img_fit_contain" alt="" height="75" width="75" src='@Ecom.GetImage(imageCustom, height:75, width:75, placeholderText:Translate("Ecom.NoImage", "No image"), placeholderTextSize: 15)'>
                        </div>
                        <!--description and price of product-->
                        <div class="col-8">
                            <h4 class="fw_medium m_bottom_10">@p.GetString("Ecom:Product.Name")</h4>
                            <p>
                                @Translate("Ecom.ProductNumber"): @p.GetString("Ecom:Product.Number")<br /> @salesPrice
                                @(!string.IsNullOrEmpty(p.GetString("Ecom:Product.ShortDescription")) ? p.GetString("Ecom:Product.ShortDescription") + "<br/>" : string.Empty)
                                @*@Translate("Ecom.SalesPrice"): @p.GetString("Ecom:Product.Discount.Price.PriceWithoutVATFormatted")<br />
                                    @Translate("Ecom.ListIncl"): @salesPrice.ToString("C")*@
                            </p>
                        </div>
                        <div class="col-12">

                            @*OK, lets fire this off, Multiform wrapped around a table for each of the variations.
                                This is a proper Loop Bonanza! Yihaa! *@
                            @if (varComb.Count > 0)
                            {
                                <div class="clearfix m_top_15 bg_color_white">
                                    <table class="variant_table preorder_table w-100">
                                        @*Table head, loop throug the Size variant group, becasue there will allways be sizes as variation...  (?) *@
                                        @foreach (LoopItem sizes in p.GetLoop("VariantGroups").Where(x => x.GetString("Ecom:VariantGroup.Name") == "SIZE"))
                                        {
                                            <tr>
                                                <td>@Translate("VariantTableName", "Color/Size")</td>

                                                @foreach (LoopItem size in sizes.GetLoop("VariantAvailableOptions"))
                                                {
                                                    <td class="t_align_c">@size.GetString("Ecom:VariantOption.Name")</td>
                                                }
                                                <td class="t_align_c">Sum antall</td>
                                                <td class="t_align_c">Pris</td>
                                                <td class="t_align_c">Sum pris</td>
                                            </tr>
                                        }

                                        @*Then if there is a second varition, eg. Color, we loop throught that group, giving each rows first cell the name of the variation. Then we create the rest of the cells by looping through each size option. We do this for each row of color varition. The input takes a Variant ID made from the rows color ID and the size ID.*@
                                        @if ((p.GetLoop("VariantGroups").Where(x => x.GetString("Ecom:VariantGroup.Name") == "COLOR")).Count() > 0)
                                        {

                                            foreach (LoopItem vgColor in p.GetLoop("VariantGroups").Where(x => x.GetString("Ecom:VariantGroup.Name") == "COLOR"))
                                            {

                                                @*Looping throught the row labels, first cell*@
                                                foreach (LoopItem voColor in vgColor.GetLoop("VariantAvailableOptions"))
                                                {
                                                    string rowId = string.Format("colorRow{0}", rowCounter);

                                                    <tr id="@rowId">
                                                        <th>@voColor.GetString("Ecom:VariantOption.Name")</th>
                                                        @*Then we create inputs for all the options. *@

                                                        @foreach (LoopItem vgSize in p.GetLoop("VariantGroups").Where(x => x.GetString("Ecom:VariantGroup.Name") == "SIZE"))
                                                        {
                                                            var price = string.Empty;
                                                            var priceClean = string.Empty;

                                                            foreach (LoopItem voSize in vgSize.GetLoop("VariantAvailableOptions"))
                                                            {
                                                                @*NB, what comes first, SIZE OR COLOR*@
                                                                var varOptId = string.Format("{1}.{0}", voSize.GetString("Ecom:VariantOption.ID"), voColor.GetString("Ecom:VariantOption.ID"));
                                                                var varCombination = varComb.Where(x => x.GetString("Ecom:Product.VariantID") == varOptId);

                                                                <td>
                                                                    @foreach (LoopItem vc in varCombination)
                                                                    {
                                                                        price = vc.GetString("Ecom:Product.Price");
                                                                        priceClean = vc.GetString("Ecom:Product.DBPrice");

                                                                        <input type="hidden" name="ProductLoopCounter@(c)" id="ProductLoopCounter@(c)" value="@(c)">
                                                                        <input type="hidden" name="ProductID@(c)" id="ProductID@(c)" value="@p.GetValue("Ecom:Product.ID")" />
                                                                        <input type="hidden" name="VariantID@(c)" value="@vc.GetString("Ecom:Product.VariantID")" />
                                                                        <input type="number" class="w-100 t_align_c qty" name="Quantity@(c)" value="" onchange="updateRowQuantity(@rowId)" /> @*@Translate(" Ecom:Product.Delimiter", " stk.")*@
                                                                        @*<input type="hidden" class="ProductVarPrice" value="@vc.GetValue("Ecom:Product.Price")" />*@

                                                                    }
                                                                </td>
                                                                c++;
                                                            }

                                                            <td class="Quantity"></td>
                                                            <td class="Price" data-price="@priceClean">@price</td>
                                                            <td class="SumPrice"></td>
                                                            rowCounter++;
                                                        }

                                                    </tr>
                                                }

                                            }
                                        }
                                        else
                                        {
                                            <tr>
                                                <td></td>
                                                @*This is simpler, we just need an input for each size variation.*@
                                                @foreach (var vg in p.GetLoop("VariantGroups"))
                                                {
                                                    foreach (LoopItem vo in vg.GetLoop("VariantAvailableOptions"))
                                                    {
                                                        var varOptId = string.Format("{0}", vo.GetString("Ecom:VariantOption.ID"));
                                                        <td>
                                                            @foreach (LoopItem vc in varComb.Where(x => x.GetString("Ecom:Product.VariantID") == varOptId))
                                                            {
                                                                if (vc.GetDouble("Ecom:VariantCombination.Product.Stock") > 0)
                                                                {
                                                                    <input type="hidden" name="ProductLoopCounter@(c)" id="ProductLoopCounter@(c)" value="@(c)">

                                                                    <input type="hidden" name="ProductID@(c)" id="ProductID@(c)" value="@p.GetValue("Ecom:Product.ID")" />

                                                                    <input type="hidden" name="VariantID@(c)" value="@varOptId" />

                                                                    <input type="number" class="" name="Quantity@(c)" value="" /> @Translate(" Ecom:Product.Delimiter", " stk.")
                                                                }
                                                                else
                                                                {
                                                                    <em>@Translate("Ecom.Product.Stock.Empty", "Tomt på lager")</em>
                                                                }
                                                            }
                                                        </td>
                                                        c++;
                                                    }
                                                }
                                            </tr>
                                        }

                                    </table>

                                </div>
                            }
                            else
                            {

                            }

                            @*Submit the form, and all is well. You can now ride into the Loopy sunset.*@
                        </div>
                    </div>
                </div>

                <hr class="m-3" />
                c++;
            }

            <div id="afterProducts"></div>

            <input type="hidden" name="OrderContext" value="PreOrders" />
            <div id="addToPreorderCart" class="fixed-bottom bg_color_white box-shadow">
                <div class="container">
                    <a class="button_type_4 color_dark bg_light_color_1 d_block r_corners tr_delay_hover box_s_none f_left m-2" href="/preordercart">@Translate("Ecom.Preorder.Cart", "Preorder kurv")</a>
                    <button id="addToPreorderCartSubmit" type="button" class="button_type_3 color_light bg_scheme_color d_block r_corners tr_delay_hover box_s_none f_right m-2"><i class="fa fa-cart-plus m_left_5 m_right_10 f_size_large"></i>@Translate("Ecom.Preorder.Buy.All", "Legg varene i preorder kurven")</button>
                </div>
            </div>
        </form>
    </div>
</div>
 
Nicolai Pedersen
Reply

Hi Bjørn

Try to catch the add to cart post command in your browser developer tools and check if that looks ok - look at the post body and querystring of the command. If that does not give you any pointers, try posting them here.

BR Nicolai

 
Bjørn Kamfjord
Reply

I log the serialized form that gets passed. As far as I can see, there is nothing wrong?

the log: I've highlighted the producyts with Quantity values.

CartCmd=addMulti&ProductLoopCounter1=1&ProductID1=9907105&VariantID1=COLOR400.SIZE35-39&Quantity1=&ProductLoopCounter2=2&ProductID2=9907105&VariantID2=COLOR400.SIZE40-47&Quantity2=&ProductLoopCounter4=4&ProductID4=9900893&VariantID4=COLOR900.SIZE2XL&Quantity4=1&ProductLoopCounter5=5&ProductID5=9900893&VariantID5=COLOR900.SIZE3XL&Quantity5=2&ProductLoopCounter6=6&ProductID6=9900893&VariantID6=COLOR900.SIZEXS&Quantity6=4&ProductLoopCounter8=8&ProductID8=9900890&VariantID8=COLOR409.SIZE2XL&Quantity8=&ProductLoopCounter9=9&ProductID9=9900890&VariantID9=COLOR409.SIZE3XL&Quantity9=&ProductLoopCounter10=10&ProductID10=9900890&VariantID10=COLOR409.SIZEXS&Quantity10=&ProductLoopCounter12=12&ProductID12=9900888&VariantID12=COLOR900.SIZE2XL&Quantity12=&ProductLoopCounter13=13&ProductID13=9900888&VariantID13=COLOR900.SIZE3XL&Quantity13=&ProductLoopCounter15=15&ProductID15=9900875&VariantID15=COLOR400.SIZEONE&Quantity15=&ProductLoopCounter17=17&ProductID17=9900498&VariantID17=COLOR900.SIZE2XL&Quantity17=&ProductLoopCounter18=18&ProductID18=9900498&VariantID18=COLOR900.SIZE3XL&Quantity18=&ProductLoopCounter19=19&ProductID19=9900498&VariantID19=COLOR900.SIZEXS&Quantity19=&ProductLoopCounter21=21&ProductID21=9900488&VariantID21=COLOR900.SIZE2XL&Quantity21=&ProductLoopCounter22=22&ProductID22=9900488&VariantID22=COLOR900.SIZE3XL&Quantity22=&ProductLoopCounter23=23&ProductID23=9900488&VariantID23=COLOR900.SIZEXS&Quantity23=&ProductLoopCounter25=25&ProductID25=9200061&VariantID25=COLOR100.SIZE2XL&Quantity25=&ProductLoopCounter28=28&ProductID28=9200011&VariantID28=COLOR100.SIZE2XL&Quantity28=&ProductLoopCounter30=30&ProductID30=9150790&VariantID30=COLOR900.SIZE2XL&Quantity30=&ProductLoopCounter32=32&ProductID32=9150788&VariantID32=COLOR900.SIZE2XL&Quantity32=&OrderContext=PreOrders
 
Bjørn Kamfjord
Reply

Do you see anything on this response that is wrong?

 

 
Morten Bengtson Dynamicweb Employee
Morten Bengtson
Reply

I can't spot anything wrong in that request, but there is something wrong with the imported products. When you try to view the variants of a product you get an error message. It seems like the variants have not been imported correctly. Can you test your templates on a Dynamicweb installation without any imported data?

 

You must be logged in to post in the forum