目標
製品の動的リストを作成します。
シナリオ
製品を含むショッピング アプリケーションがあります。商品の をクリックしたときにadd button
、追加した商品をサイドバーに表示したい。
要約された問題 (これを読む必要があります)
私はProductsSummary/Index.cshtml
(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>
ご覧のとおり<li>
、コードには 3 つあります。1 つ目は、「概要が空です」というメッセージを表示することです。セッションが null の場合 (もちろん、製品が追加された場合、Session は null です)。2 番目li
は、セッションが null のときに何かを追加するときの Knockout のモデルとして機能します。最後に、セッションにある製品を表示します。
ここは少し「ドライ」な感じです。セッションが存在するかどうかに関係なく、同じテンプレートを再利用するにはどうすればよいですか?
詳細な問題
私はProductsSummary/Index.cshtml
(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>
ご覧のとおり、セッションが存在するif
かどうかをチェックする があります。ProductsSummary
はいの場合、アプリケーションは、概要に追加した製品のリストを画面に表示します。
ご覧のとおり、セッションが nullli
の場合、アプリケーションはwithis-empty
クラス内にメッセージを表示します。
ポイントは、要約に追加されたアイテムを表示するために「テンプレート」が本当に必要かということです。<li class="is-empty">[...]</li>
つまり、セッションの有無に関係なく、[製品の追加] ボタンをクリックしたときに Knockout に何かを表示する必要があることはわかっていますが、同様の目的で同じテンプレートを繰り返しています。
このフラグメントを見てください:
<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>
この場合、foreach
データベースから取得したアイテムを表示する必要があるため、内部で使用しています。
一方、セッションがない場合、次のフラグメントが存在します。
<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>
ご覧のとおり、両方のフラグメントは似ています — 1 つはデータベースからのデータを表し、もう 1 つはセッションがない場合に Knockout で動作するモデルをそれぞれ表します — これを「テンプレート化」する方法が必要です。
本当に必要なもの
- 誰かが私のサイト/アプリケーションに入ります。
- 私のレイアウトの右側には、「概要が空です。」というメッセージが表示されたサイドバーがあります。
- 「ああ、なんて素晴らしい製品でしょう! サマリーに追加します!」ユーザー
Add
は、「サマリーが空です」というボタンをクリックします。メッセージが消え、ユーザーが追加した製品がリストのアイテムの形式で表示されます ([最初/2 番目のフラグメント] の前に渡したのと同じテンプレート)。- 「わかりました。今から別のカテゴリの製品に移動します。」— *ユーザーは「テレビ」カテゴリをクリックします* — 「なんてこった! このテレビを見てください! 今すぐ要約に追加します!」— *ユーザーが任意の TV の [追加] ボタンをクリックします。* — リストには既に製品がありましたが、別の (TV) が表示されました。
- 「ああ、気にしないでください。私はお金を持っていません。これらのアイテムを私の概要から削除します。」— *ユーザーはサマリーで各製品の「削除ボタン」をクリックします* — 製品がない場合、サマリーには「サマリーは空です」と表示されます。魔法のように、リフレッシュなどはありません。
(おかしいでしょ?)
KnockoutJS スクリプト
$(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") }
});
});
});
結局、何が起こっているのですか?
私がやっていることは機能し、機能しません。技術的には、私のコードは機能しますが、繰り返したくありません。出来ますか?
技術的な詳細
サーバー側のチームはMVC 4 と Razor Engineを使用する C#.NET を使用し、クライアント側のチームはKnockoutJS と jQuery を使用します。