Část 7: Vytvoření hlavní stránky

Rick Anderson

Stažení dokončeného projektu

Vytvoření hlavní stránky

V této části vytvoříte hlavní stránku aplikace. Tato stránka bude složitější než stránka Správa, takže se k ní budeme blížit v několika krocích. Na této cestě uvidíte některé pokročilejší techniky Knockout.js. Tady je základní rozložení stránky:

Diagram interakce mezi prvky hlavní stránky, košíkem, objednávkami a podrobnostmi objednávek

Diagram interakce mezi prvky hlavní stránky, košíkem, objednávkami a podrobnostmi objednávek Element products je označený GET A P I / products se šipkou ukazující na prvek items. Element items je připojen k prvku orders pomocí šipky označené POST A P I / orders. Element orders je připojený k prvku details pomocí šipky označené GET A P I / orders. Element details je označen GET A P I / orders / i d.

  • "Produkty" obsahují řadu produktů.
  • "Košík" obsahuje pole produktů s množstvím. Kliknutím na Přidat do košíku se košík aktualizuje.
  • "Objednávky" obsahují pole ID objednávek.
  • "Podrobnosti" obsahují podrobnosti objednávky, což je pole položek (produkty s množstvím).

Začneme definováním základního rozložení v HTML bez datové vazby nebo skriptu. Otevřete soubor Views/Home/Index.cshtml a nahraďte veškerý obsah následujícím kódem:

<div class="content">
    <!-- List of products -->
    <div class="float-left">
    <h1>Products</h1>
    <ul id="products">
    </ul>
    </div>

    <!-- Cart -->
    <div id="cart" class="float-right">
    <h1>Your Cart</h1>
        <table class="details ui-widget-content">
    </table>
    <input type="button" value="Create Order"/>
    </div>
</div>

<div id="orders-area" class="content" >
    <!-- List of orders -->
    <div class="float-left">
    <h1>Your Orders</h1>
    <ul id="orders">
    </ul>
    </div>

   <!-- Order Details -->
    <div id="order-details" class="float-right">
    <h2>Order #<span></span></h2>
    <table class="details ui-widget-content">
    </table>
    <p>Total: <span></span></p>
    </div>
</div>

Dále přidejte oddíl Scripts (Skripty) a vytvořte prázdný view-model:

@section Scripts {
  <script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.1.0.js")"></script>
  <script type="text/javascript">

    function AppViewModel() {
        var self = this;
        self.loggedIn = @(Request.IsAuthenticated ? "true" : "false");
    }

    $(document).ready(function () {
        ko.applyBindings(new AppViewModel());
    });

  </script>
}

Na základě návrhu načrtnutého dříve potřebuje náš model zobrazení sledovatelné údaje týkající se produktů, košíků, objednávek a podrobností. Přidejte do objektu AppViewModel následující proměnné:

self.products = ko.observableArray();
self.cart = ko.observableArray();
self.orders = ko.observableArray();
self.details = ko.observable();

Uživatelé můžou přidávat položky ze seznamu produktů do košíku a odebírat položky z košíku. K zapouzdření těchto funkcí vytvoříme další třídu view-model, která představuje produkt. Do souboru AppViewModel přidejte následující kód:

function AppViewModel() {
    // ...

    // NEW CODE
    function ProductViewModel(root, product) {
        var self = this;
        self.ProductId = product.Id;
        self.Name = product.Name;
        self.Price = product.Price;
        self.Quantity = ko.observable(0);

        self.addItemToCart = function () {
            var qty = self.Quantity();
            if (qty == 0) {
                root.cart.push(self);
            }
            self.Quantity(qty + 1);
        };

        self.removeAllFromCart = function () {
            self.Quantity(0);
            root.cart.remove(self);
        };
    }
}

Třída ProductViewModel obsahuje dvě funkce, které se používají k přesunu produktu do a z košíku: addItemToCart přidá do košíku jednu jednotku produktu a removeAllFromCart odebere všechna množství produktu.

Uživatelé můžou vybrat existující objednávku a získat podrobnosti o objednávce. Tuto funkci zapouzdřeme do jiného modelu zobrazení:

function AppViewModel() {
    // ...

    // NEW CODE
    function OrderDetailsViewModel(order) {
        var self = this;
        self.items = ko.observableArray();
        self.Id = order.Id;

        self.total = ko.computed(function () {
            var sum = 0;
            $.each(self.items(), function (index, item) {
                sum += item.Price * item.Quantity;
            });
            return '$' + sum.toFixed(2);
        });

        $.getJSON("/api/orders/" + order.Id, function (order) {
            $.each(order.Details, function (index, item) {
                self.items.push(item);
            })
        });
    };
}

Inicializuje OrderDetailsViewModel se s objednávkou a načte podrobnosti objednávky odesláním požadavku AJAX na server.

Všimněte si total také vlastnosti .OrderDetailsViewModel Tato vlastnost je speciální druh pozorovatelného, kterému se říká vypočítaný pozorovatelný. Jak název napovídá, vypočítaný pozorovatelný umožňuje vytvořit vazbu dat na vypočítanou hodnotu – v tomto případě celkové náklady na objednávku.

Dále přidejte tyto funkce do AppViewModel:

  • resetCart odebere všechny položky z košíku.
  • getDetails získá podrobnosti o objednávce (vložením nového OrderDetailsViewModel příkazu do details seznamu).
  • createOrder vytvoří novou objednávku a vyprázdní košík.
function AppViewModel() {
    // ...

    // NEW CODE
    self.resetCart = function() {
        var items = self.cart.removeAll();
        $.each(items, function (index, product) {
            product.Quantity(0);
        });
    }

    self.getDetails = function (order) {
        self.details(new OrderDetailsViewModel(order));
    }

    self.createOrder = function () {
        var jqxhr = $.ajax({
            type: 'POST',
            url: "api/orders",
            contentType: 'application/json; charset=utf-8',
            data: ko.toJSON({ Details: self.cart }),
            dataType: "json",
            success: function (newOrder) {
                self.resetCart();
                self.orders.push(newOrder);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                self.errorMessage(errorThrown);
            }  
        });
    };
};

Nakonec inicializujte model zobrazení tak, že odešlete požadavky AJAX na produkty a objednávky:

function AppViewModel() {
    // ...

    // NEW CODE
    // Initialize the view-model.
    $.getJSON("/api/products", function (products) {
        $.each(products, function (index, product) {
            self.products.push(new ProductViewModel(self, product));
        })
    });

    $.getJSON("api/orders", self.orders);
};

Dobře, to je hodně kódu, ale vytvořili jsme ho krok za krokem, takže doufejme, že návrh je jasný. Teď můžeme do HTML přidat několik Knockout.js vazeb.

Produkty

Tady jsou vazby pro seznam produktů:

<ul id="products" data-bind="foreach: products">
    <li>
        <div>
            <span data-bind="text: Name"></span> 
            <span class="price" data-bind="text: '$' + Price"></span>
        </div>
        <div data-bind="if: $parent.loggedIn">
            <button data-bind="click: addItemToCart">Add to Order</button>
        </div>
    </li>
</ul>

To iteruje pole produktů a zobrazí název a cenu. Tlačítko "Přidat do objednávky" se zobrazí, jenom když je uživatel přihlášený.

Tlačítko Add to Order (Přidat do objednávky) volá addItemToCartProductViewModel instanci produktu. To ukazuje dobrou funkci Knockout.js: Pokud view-model obsahuje další modely zobrazení, můžete použít vazby na vnitřní model. V tomto příkladu se vazby v rámci objektu foreach použijí na každou instanci ProductViewModel . Tento přístup je mnohem čistší než uvedení všech funkcí do jediného modelu zobrazení.

Košík

Tady jsou vazby pro košík:

<div id="cart" class="float-right" data-bind="visible: cart().length > 0">
<h1>Your Cart</h1>
    <table class="details ui-widget-content">
    <thead>
        <tr><td>Item</td><td>Price</td><td>Quantity</td><td></td></tr>
    </thead>    
    <tbody data-bind="foreach: cart">
        <tr>
            <td><span data-bind="text: $data.Name"></span></td>
            <td>$<span data-bind="text: $data.Price"></span></td>
            <td class="qty"><span data-bind="text: $data.Quantity()"></span></td>
            <td><a href="#" data-bind="click: removeAllFromCart">Remove</a></td>
        </tr>
    </tbody>
</table>
<input type="button" data-bind="click: createOrder" value="Create Order"/>

Iteruje se v poli košíku a zobrazí se název, cena a množství. Všimněte si, že odkaz "Odebrat" a tlačítko "Vytvořit objednávku" jsou vázány na funkce view-model.

Orders (Objednávky)

Tady jsou vazby pro seznam objednávek:

<h1>Your Orders</h1>
<ul id="orders" data-bind="foreach: orders">
<li class="ui-widget-content">
    <a href="#" data-bind="click: $root.getDetails">
        Order # <span data-bind="text: $data.Id"></span></a>
</li>
</ul>

To iteruje objednávky a zobrazuje ID objednávky. Událost click na odkazu je vázaná na getDetails funkci .

Podrobnosti objednávky

Tady jsou vazby pro podrobnosti objednávky:

<div id="order-details" class="float-right" data-bind="if: details()">
<h2>Order #<span data-bind="text: details().Id"></span></h2>
<table class="details ui-widget-content">
    <thead>
        <tr><td>Item</td><td>Price</td><td>Quantity</td><td>Subtotal</td></tr>
    </thead>    
    <tbody data-bind="foreach: details().items">
        <tr>
            <td><span data-bind="text: $data.Product"></span></td>
            <td><span data-bind="text: $data.Price"></span></td>
            <td><span data-bind="text: $data.Quantity"></span></td>
            <td>
                <span data-bind="text: ($data.Price * $data.Quantity).toFixed(2)"></span>
            </td>
        </tr>
    </tbody>
</table>
<p>Total: <span data-bind="text: details().total"></span></p>
</div>

Tím se iteruje položky v objednávce a zobrazí se produkt, cena a množství. Okolní div je viditelný pouze v případě, že pole podrobností obsahuje jednu nebo více položek.

Závěr

V tomto kurzu jste vytvořili aplikaci, která ke komunikaci s databází používá Entity Framework, a ASP.NET webové rozhraní API, aby poskytovalo veřejné rozhraní nad datovou vrstvou. K vykreslení stránek HTML používáme ASP.NET MVC 4 a Knockout.js a jQuery k zajištění dynamických interakcí bez opětovného načtení stránky.

Další prostředky: