购物车逻辑(?)与KnockoutJS麻烦 [英] Shopping Cart logic (?) trouble with KnockoutJS

查看:269
本文介绍了购物车逻辑(?)与KnockoutJS麻烦的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标



请产品的动态列表。



场景



我有产品购物应用程序。当我点击添加按钮的一款产品,我想在侧边栏,我已经添加什么产品来显示。



总结问题(你只需要阅读本)



我在 ProductsSummary / Index.cshtml (使用剃刀引擎):

 < UL类=摘要> 
@if(会话[ProductsSummary] == NULL)
{
<李班=是空的>
< P>您的总结是空< / P>
< /李>
<李数据绑定=ATTR:{'数据产品ID:ID}>
< DIV CLASS =产品汇总行动自由流通的权利>
<按钮类=BTN BTN-危险BTN-迷你删除项目>
< I类=图标删除>< I> /;
< /按钮>
< / DIV>
< DIV CLASS =产品汇总量>
< H6数据绑定=TEXT:infoComposition>< / H6>
< / DIV>
< DIV CLASS =产品汇总描述>
< P数据绑定=TEXT:名称>< / P>
< / DIV>
< /李>
}
,否则
{
的foreach
(在
变种产品(名单< MyApp.Models.Data.getSpecificProductToShoppingList_Result>)
会话[ ProductsSummary])
{
< - 阁的foreach:产品 - >
<李数据产品ID =@ product.id>
< DIV CLASS =产品汇总行动自由流通的权利>
<按钮类=BTN BTN-危险BTN-迷你删除项目>
< I类=图标删除>< I> /;
< /按钮>
< / DIV>
< DIV CLASS =产品汇总量>
<&H6 GT;
@ product.quantity
@ product.measure @(@ product.quantity == 1:S)
< / H6>
< / DIV>
< DIV CLASS =产品汇总描述>
< P> @ product.name< / P>
< / DIV>
< /李>
<! - / KO - >
}
}
< / UL>



正如你所看到的,有为三<李> 中的代码。第一个是与显示一个消息的摘要是空的。区分会话为空(当然,会话为空情况下,任何产品已被添加);第二个作为模型淘汰赛时,我补充一点,当会话为null;以及最后一个是要显示的内容是在会话的产品



我感觉有点的 DRY 的就在这里。我怎么能不管是否存在会话,或者不重复使用相同的模板?



详细的问题



我有下面的代码我的 ProductsSummary / Index.cshtml (使用剃刀引擎):

 < UL类=摘要> 
@if(会话[ProductsSummary] == NULL)
{
<李班=是空的>
< P>您的总结是空< / P>
< /李>
<李数据绑定=ATTR:{'数据产品ID:ID}>
< DIV CLASS =产品汇总行动自由流通的权利>
<按钮类=BTN BTN-危险BTN-迷你GT&;
< I类=图标删除>< I> /;
< /按钮>
< / DIV>
< DIV CLASS =产品汇总量>
< H6数据绑定=TEXT:infoComposition>< / H6>
< / DIV>
< DIV CLASS =产品汇总描述>
< P数据绑定=TEXT:名称>< / P>
< / DIV>
< /李>
}
,否则
{
的foreach
(在
变种产品(名单< MyApp.Models.Data.getSpecificProductToShoppingList_Result>)
会话[ ProductsSummary])
{
< - 阁的foreach:产品 - >
<李数据产品ID =@ product.id>
< DIV CLASS =产品汇总行动自由流通的权利>
<按钮类=BTN BTN-危险BTN-迷你删除项目>
< I类=图标删除>< I> /;
< /按钮>
< / DIV>
< DIV CLASS =产品汇总量>
<&H6 GT;
@ product.quantity
@ product.measure @(@ product.quantity == 1:S)
< / H6>
< / DIV>
< DIV CLASS =产品汇总描述>
< P> @ product.name< / P>
< / DIV>
< /李>
<! - KO - >
}
}
< / UL>



正如你可以看到,有一个如果,检查是否 ProductsSummary 会话存在。如果是的话,那么应用程序显示在屏幕中,我对我的总结附加值产品名单上。



案例会话的为空的,因为你可以看到,应用程序将显示为空类。

$ b内部消息
$ b

问题的关键是:我的真正需要模板后<李班=是─空> [...] LT; /李> 来显示被添加到汇总的项目



我的意思是,我知道,淘汰赛需要的东西,以显示当我点击添加产品键,则不论是否有一个会议,但我重复类似用途相同的模板。



看这个片断:

 <李数据产品ID =@ product.id> 
< DIV CLASS =产品汇总行动自由流通的权利>
<按钮类=BTN BTN-危险BTN-迷你删除项目>
< I类=图标删除>< I> /;
< /按钮>
< / DIV>
< DIV CLASS =产品汇总量>
<&H6 GT;
@ product.quantity
@ product.measure @(@ product.quantity == 1:S)
< / H6>
< / DIV>
< DIV CLASS =产品汇总描述>
< P> @ product.name< / P>
< / DIV>
< /李>

在这种情况下,我用它在的foreach ,因为我必须来显示从数据库中获取的项目



在另一方面,如果没有一个会话下面的代码片段存在:

 <李数据绑定=ATTR:{'数据产品ID:ID}> 
< DIV CLASS =产品汇总行动自由流通的权利>
<按钮类=BTN BTN-危险BTN-迷你GT&;
< I类=图标删除>< I> /;
< /按钮>
< / DIV>
< DIV CLASS =产品汇总量>
< H6数据绑定=TEXT:infoComposition>< / H6>
< / DIV>
< DIV CLASS =产品汇总描述>
< P数据绑定=TEXT:名称>< / P>
< / DIV>
< /李>



正如你所看到的两个片段是相似的 - 一个代表从数据库中的数据,另代表模型淘汰赛工作的时候没有会话,分别为 - 我需要一种方法来模板化这个



我真正需要的





  1. 有人在我的网站/应用程序进入;

  2. 在我的布局右侧还有一个消息,侧边栏:总结为空;

  3. !唉,真是一个好产品,我将它添加到我的总结,那么用户点击添加按钮,将总结是空的。信息消失,用户添加的产品出现在一个项目的格式从列表(即我以前[第一/第二个片段]通过了相同的模板)。

  4. 好吧,我会以产品的另外一类了。 - *用户点击电视类别* - !OH MY GOD看这个电视,我将添加到我的总结,现在! - *用户点击添加按钮随机电视* - 已经有了列表中的产品,但另一个(电视)出现

  5. 哦,请不要介意我。没有钱,我会从我的摘要中删除这些项目。 - *用户点击删除按钮上的摘要*每个产品的 - 而如果没有产品,摘要显示:总结是空的。就像一个神奇的,没有任何刷新或这样的事情。




(搞怪,是吧?)



的KnockoutJS脚本



  $ (文件)。就绪(函数(){
功能的产品(ID,名称,测量,数量){
this.id = ko.observable(ID);
this.name =高.observable(名);
this.measure = ko.computed(函数(){
返回数量> 1 +计量S:措施;
},这一点);
this.quantity = ko.observable(数量);
this.infoComposition = ko.computed(函数(){
返回this.quantity()++ this.measure()
},这一点);
}

功能SummaryViewModel(){
this.products = ko.observableArray([]);

this.addToSummary =功能(formElement){
变量$的productId = $(formElement)。儿童([名称=的productId])VAL();

变种匹配= $( 。总结)
.find(李[数据产品ID =+ $的productId +])的长度。

如果(!比赛){
$ VAR =产品名称
$(formElement)。儿童([名称=产品名称])。VAL(),
$ productMeasure =
$(formElement)。儿童([名称= productMeasure])。VAL(),
$ =产品数量
$(formElement)。儿童([名称=产品数量])VAL();

this.products.push
(新产品
($的productId,
$产品名称,
$ productMeasure,
$产品数量)) ;

$阿贾克斯({
型:POST,
URL:/ ProductsSummary /添加,
数据:
{
产品编号:$的productId,
产品数量:$产品数量
}
});
}
}
};

变种summaryViewModel =新SummaryViewModel();
ko.applyBindings(summaryViewModel);

$(身体)上(点击,卸下摆臂项功能(){
summaryViewModel.products.remove(ko.dataFor(本))。

$阿贾克斯({
型:POST,
URL:/ ProductsSummary /删除,
数据:{产品编号:$(本)。最接近(礼)的数据(产品ID)}
});
});
});



这是怎么回事,最后?



我在做什么工作和不工作。从技术上讲,我的代码工作,但我不会重复。这可能吗?



技术细节



服务器端的团队是的 C#.NET与MVC 4和剃刀引擎的与客户端团队的 KnockoutJS和jQuery


解决方案

有关空的购物车信息,你可以这样做:

 <李班=是空的数据绑定=看得见:产品(5)长度。1> 
< P>您的总结是空< / P>
< /李>

有关休息,你应该能够做到这一点(不MVC循环):

 <  - 阁的foreach:产品 - > 
<李数据绑定=ATTR:{'数据产品ID:ID}>
< DIV CLASS =产品汇总行动自由流通的权利>
<按钮类=BTN BTN-危险BTN-迷你删除项目>
< I类=图标删除>< I> /;
< /按钮>
< / DIV>
< DIV CLASS =产品汇总量>
< H6数据绑定=TEXT:infoComposition>< / H6>
< / DIV>
< DIV CLASS =产品汇总描述>
< P数据绑定=TEXT:名称>< / P>
< / DIV>
< /李>
<! - / KO - >

和填充在客户端列表中,即使你有保存到会话中的项目。在您看来,现有数据序列化到一个JSON对象并将其保存到页面上的JavaScript变量可以在文档准备好被读取并推入产品可观察的。

  VAR existingItems = @ Html.Raw(Json.Encode((名单< MyApp.Models.Data.getSpecificProductToShoppingList_Result>)会议[ProductsSummary])); 

$(文件)。就绪(函数(){
//推入existingItems观察到的产品
});

请注意我的语法可能不是很正确的JSON编码。


The Goal

Make a dynamic list of products.

The Scenario

I have a shopping application with products. When I click on the add button of a product, I want to display in the sidebar, the product what I have added.

Summarized Problem (You just need to read this)

I have the following code in my ProductsSummary/Index.cshtml (using Razor Engine):

<ul class="summary">
    @if (Session["ProductsSummary"] == null)
    {
        <li class="is-empty">
            <p>Your summary is empty.</p>
        </li>
        <li data-bind="attr: { 'data-product-id': id }">
            <div class="product-summary-actions float-right">
                <button class="btn btn-danger btn-mini remove-item">
                    <i class="icon-remove"></i>
                </button>
            </div>
            <div class="product-summary-quantity">
                <h6 data-bind="text: infoComposition"></h6>
            </div>
            <div class="product-summary-description">
                <p data-bind="text: name"></p>
            </div>
        </li>
    }
    else
    {
        foreach 
          (var product in 
             (List<MyApp.Models.Data.getSpecificProductToShoppingList_Result>)
                Session["ProductsSummary"])
        {
        <!-- ko foreach: products -->
        <li data-product-id="@product.id">
            <div class="product-summary-actions float-right">
                <button class="btn btn-danger btn-mini remove-item">
                    <i class="icon-remove"></i>
                </button>
            </div>
            <div class="product-summary-quantity">
                <h6>
                   @product.quantity 
                   @product.measure@(@product.quantity == 1 ? "" : "s")
                </h6>
            </div>
            <div class="product-summary-description">
                <p>@product.name</p>
            </div>
        </li>
        <!-- /ko -->
        }
    }
</ul>

As you can see, there is three <li> on the code. The first is to display a message with "The summary is empty." case the session is null (and of course, the Session is null case any product has been added); the second li serves as model for Knockout when I add something when the session is null; and the last one is to display the products what are in the session.

I'm feeling a little "DRY" right here. How can I reuse the same template regardless of whether session exists or not?

Detailed Problem

I have the following code in my ProductsSummary/Index.cshtml (using Razor Engine):

<ul class="summary">
    @if (Session["ProductsSummary"] == null)
    {
        <li class="is-empty">
            <p>Your summary is empty.</p>
        </li>
        <li data-bind="attr: { 'data-product-id': id }">
            <div class="product-summary-actions float-right">
                <button class="btn btn-danger btn-mini">
                    <i class="icon-remove"></i>
                </button>
            </div>
            <div class="product-summary-quantity">
                <h6 data-bind="text: infoComposition"></h6>
            </div>
            <div class="product-summary-description">
                <p data-bind="text: name"></p>
            </div>
        </li>
    }
    else
    {
        foreach 
          (var product in 
             (List<MyApp.Models.Data.getSpecificProductToShoppingList_Result>)
                Session["ProductsSummary"])
        {
        <!-- ko foreach: products -->
        <li data-product-id="@product.id">
            <div class="product-summary-actions float-right">
                <button class="btn btn-danger btn-mini remove-item">
                    <i class="icon-remove"></i>
                </button>
            </div>
            <div class="product-summary-quantity">
                <h6>
                   @product.quantity 
                   @product.measure@(@product.quantity == 1 ? "" : "s")
                </h6>
            </div>
            <div class="product-summary-description">
                <p>@product.name</p>
            </div>
        </li>
        <!-- ko -->
        }
    }
</ul>

As you can see, there is an if that checks if ProductsSummary session exists. If yes, then the application displays on the screen a list of products that I added on my summary.

Case the session is null, as you can see, the application displays the message within the li with is-empty class.

The point is: I really need of the "template" after <li class="is-empty">[...]</li> to display an item that was added to the summary?

I mean, I know that Knockout needs something to display when I click the "Add Product" button regardless of whether or not there is a session, but I'm repeating the same template for similar purposes.

Look to this fragment:

<li data-product-id="@product.id">
    <div class="product-summary-actions float-right">
        <button class="btn btn-danger btn-mini remove-item">
            <i class="icon-remove"></i>
        </button>
    </div>
    <div class="product-summary-quantity">
        <h6>
           @product.quantity 
           @product.measure@(@product.quantity == 1 ? "" : "s")
        </h6>
    </div>
    <div class="product-summary-description">
        <p>@product.name</p>
    </div>
</li>

In this case, I'm using it within foreach because I must to display the items fetched from the database.

On the other hand, the following fragment exists if there isn't a session:

<li data-bind="attr: { 'data-product-id': id }">
    <div class="product-summary-actions float-right">
        <button class="btn btn-danger btn-mini">
            <i class="icon-remove"></i>
        </button>
    </div>
    <div class="product-summary-quantity">
        <h6 data-bind="text: infoComposition"></h6>
    </div>
    <div class="product-summary-description">
        <p data-bind="text: name"></p>
    </div>
</li>

As you can see, the both fragments are similar — one represents the data from database, and the other represents a model to work with Knockout when there is no session, respectively — and I need a way to "templatize" this.

What I Really Need

  1. Someone enters in my site/application;
  2. At the right side of my layout there is a sidebar with a message: "The summary is empty.";
  3. "Oh, what a nice product! I will add it to my summary!", then the user clicks on Add button, the "The summary is empty." message disappears and the product added by user appears in the format of an item from a list (the same template that I have passed before [first/second fragment]).
  4. "Ok, I will to another category of products now." — *The user clicks on "TVs" category* — "OH MY GOD! Look at this TV! I will add to my summary right now!" — *The user clicks on "Add Button" of a random TV.* — Already had a product in the list, but another (the TV) appears.
  5. "Oh, nevermind. I do not have money. I will remove these items from my summary." — *The user clicks on "remove button" of each product on the summary* — And without products, the summary displays: "The summary is empty." just like a magic, without any refresh or something like this.

(Funny, huh?)

The KnockoutJS Script

$(document).ready(function () {
    function Product(id, name, measure, quantity) {
        this.id = ko.observable(id);
        this.name = ko.observable(name);
        this.measure = ko.computed(function () {
            return quantity > 1 ? measure + "s" : measure;
        }, this);
        this.quantity = ko.observable(quantity);
        this.infoComposition = ko.computed(function () {
            return this.quantity() + " " + this.measure()
        }, this);
    }

    function SummaryViewModel() {
        this.products = ko.observableArray([]);

        this.addToSummary = function (formElement) {
            var $productId = $(formElement).children("[name=productId]").val();

            var match = $(".summary")
                           .find("li[data-product-id=" + $productId + "]").length;

            if (!match) {
                var $productName = 
                        $(formElement).children("[name=productName]").val(),
                    $productMeasure = 
                        $(formElement).children("[name=productMeasure]").val(),
                    $productQuantity = 
                        $(formElement).children("[name=productQuantity]").val();

                this.products.push
                   (new Product
                       ($productId, 
                        $productName, 
                        $productMeasure, 
                        $productQuantity));

                $.ajax({
                    type: "POST",
                    url: "/ProductsSummary/Add",
                    data: 
                       { 
                         productId: $productId, 
                         productQuantity: $productQuantity 
                       }
                });
            }
        }
    };

    var summaryViewModel = new SummaryViewModel();
    ko.applyBindings(summaryViewModel);

    $("body").on("click", ".remove-item", function () {
        summaryViewModel.products.remove(ko.dataFor(this));

        $.ajax({
            type: "POST",
            url: "/ProductsSummary/Remove",
            data: { productId: $(this).closest("li").data("product-id") }
        });
    });
});

What is happening, eventually?

What I'm doing works and does not work. Technically, my code works, but I wouldn't to repeat it. Is it possible?

Technical Details

The server-side team is with C#.NET with MVC 4 and Razor Engine and the client-side team is KnockoutJS and jQuery.

解决方案

For the empty cart message, you can do this:

<li class="is-empty" data-bind="visible: products().length < 1">
    <p>Your summary is empty.</p>
</li>

For the rest, you should be able to do this (no MVC loops):

     <!-- ko foreach: products -->
     <li data-bind="attr: { 'data-product-id': id }">
        <div class="product-summary-actions float-right">
            <button class="btn btn-danger btn-mini remove-item">
                <i class="icon-remove"></i>
            </button>
        </div>
        <div class="product-summary-quantity">
            <h6 data-bind="text: infoComposition"></h6>
        </div>
        <div class="product-summary-description">
            <p data-bind="text: name"></p>
        </div>
    </li>
    <!-- /ko -->

And populate the list on the client side, even if you have items saved to the session. In your view, serialize the existing data to a JSON object and save it to a javascript variable on the page which can be read on document ready and pushed into the products observable.

var existingItems = @Html.Raw(Json.Encode((List<MyApp.Models.Data.getSpecificProductToShoppingList_Result>)Session["ProductsSummary"]));

$(document).ready(function() {
    // push existingItems into products observable.
});

Note my syntax may not be quite right on the JSON encoding.

这篇关于购物车逻辑(?)与KnockoutJS麻烦的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆