Freigeben über


Teil 7: Erstellen der Hauptseite

von Rick Anderson

Abgeschlossenes Projekt herunterladen

Erstellen der Hauptseite

In diesem Abschnitt erstellen Sie die anwendungsseitige Standard. Diese Seite ist komplexer als die Admin Seite, sodass wir sie in mehreren Schritten angehen. Auf dem Weg sehen Sie einige erweiterte Knockout.js-Techniken. Hier sehen Sie das grundlegende Layout der Seite:

Diagramm der Interaktion zwischen Produkten, Warenkorb, Bestellungen und Bestelldetails elementen einer Standard Seite.

Diagramm der Interaktion zwischen Produkten, Warenkorb, Bestellungen und Bestelldetails elementen einer Standard Seite. Das products-Element ist get A P I/products mit einem Pfeil beschriftet, der auf das element items zeigt. Das items-Element ist mit dem Orders-Element durch einen Pfeil mit der Bezeichnung POST A P I/orders verbunden. Das orders-Element ist mit dem Detailelement mit einem Pfeil mit der Bezeichnung GET A P I/orders verbunden. Das Detailelement ist lebeled GET A P I / orders / i d.

  • "Products" enthält eine Reihe von Produkten.
  • "Cart" enthält eine Reihe von Produkten mit Mengen. Durch Klicken auf "Zum Warenkorb hinzufügen" wird der Warenkorb aktualisiert.
  • "Orders" enthält ein Array von Bestell-IDs.
  • "Details" enthält ein Auftragsdetails, bei dem es sich um eine Reihe von Artikeln (Produkte mit Mengen) handelt.

Zunächst definieren wir ein grundlegendes Layout in HTML ohne Datenbindung oder Skript. Öffnen Sie die Datei Views/Home/Index.cshtml, und ersetzen Sie den gesamten Inhalt durch Folgendes:

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

Fügen Sie als Nächstes einen Skriptabschnitt hinzu, und erstellen Sie ein leeres Ansichtsmodell:

@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>
}

Basierend auf dem zuvor skizzierten Entwurf benötigt unser Ansichtsmodell Beobachtbares für Produkte, Warenkorb, Bestellungen und Details. Fügen Sie dem Objekt die folgenden Variablen hinzu AppViewModel :

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

Benutzer können Elemente aus der Produktliste in den Warenkorb hinzufügen und Elemente aus dem Warenkorb entfernen. Um diese Funktionen zu kapseln, erstellen wir eine weitere Ansichtsmodellklasse, die ein Produkt darstellt. Füge AppViewModel den folgenden Code hinzu:

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);
        };
    }
}

Die ProductViewModel Klasse enthält zwei Funktionen, die zum Verschieben des Produkts zum und aus dem Warenkorb verwendet werden: addItemToCart Fügt dem Warenkorb eine Einheit des Produkts hinzu und removeAllFromCart entfernt alle Mengen des Produkts.

Benutzer können eine vorhandene Bestellung auswählen und die Bestelldetails abrufen. Wir kapseln diese Funktionalität in ein anderes Ansichtsmodell:

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);
            })
        });
    };
}

Der OrderDetailsViewModel wird mit einer Bestellung initialisiert und ruft die Auftragsdetails ab, indem eine AJAX-Anforderung an den Server gesendet wird.

Beachten Sie auch die total -Eigenschaft für .OrderDetailsViewModel Diese Eigenschaft ist eine besondere Art von beobachtbar, die als berechnete beobachtbare Eigenschaft bezeichnet wird. Wie der Name schon sagt, können Sie mit einem berechneten beobachtbaren Daten an einen berechneten Wert binden– in diesem Fall die Gesamtkosten der Bestellung.

Fügen Sie als Nächstes die folgenden Funktionen hinzu AppViewModel:

  • resetCart entfernt alle Elemente aus dem Warenkorb.
  • getDetails ruft die Details für eine Bestellung ab (durch Pushen eines neuen OrderDetailsViewModel in die details Liste).
  • createOrder erstellt eine neue Bestellung und leert den Warenkorb.
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);
            }  
        });
    };
};

Initialisieren Sie schließlich das Ansichtsmodell, indem Sie AJAX-Anforderungen für die Produkte und Bestellungen stellen:

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);
};

Ok, das ist viel Code, aber wir haben es Schritt für Schritt aufgebaut, sodass der Entwurf hoffentlich klar ist. Jetzt können wir dem HTML-Code einige Knockout.js Bindungen hinzufügen.

Produkte

Hier sind die Bindungen für die Produktliste:

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

Dadurch wird das Produktarray durchlaufen und der Name und der Preis angezeigt. Die Schaltfläche "Zur Bestellung hinzufügen" ist nur sichtbar, wenn der Benutzer angemeldet ist.

Die Schaltfläche "Zur Bestellung hinzufügen" ruft addItemToCart die ProductViewModel instance für das Produkt auf. Dies veranschaulicht ein schönes Feature von Knockout.js: Wenn ein Ansichtsmodell andere Ansichtsmodelle enthält, können Sie die Bindungen auf das innere Modell anwenden. In diesem Beispiel werden die Bindungen innerhalb von foreach auf jede der ProductViewModel Instanzen angewendet. Dieser Ansatz ist viel sauberer, als alle Funktionen in ein einzelnes Ansichtsmodell zu integrieren.

Warenkorb

Hier sind die Bindungen für den Warenkorb:

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

Dadurch wird das Warenkorbarray durchlaufen und der Name, der Preis und die Menge angezeigt. Beachten Sie, dass der Link "Entfernen" und die Schaltfläche "Bestellung erstellen" an Ansichtsmodellfunktionen gebunden sind.

Orders

Hier sind die Bindungen für die Auftragsliste:

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

Dies durchläuft die Bestellungen und zeigt die Bestell-ID an. Das Klickereignis für den Link ist an die getDetails Funktion gebunden.

Auftragsdetails

Hier sind die Bindungen für die Bestelldetails:

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

Dies durchläuft die Artikel in der Bestellung und zeigt das Produkt, den Preis und die Menge an. Das umgebende div ist nur sichtbar, wenn das Detailsarray mindestens ein Element enthält.

Zusammenfassung

In diesem Tutorial haben Sie eine Anwendung erstellt, die Entity Framework für die Kommunikation mit der Datenbank verwendet, und ASP.NET-Web-API, eine öffentlich zugängliche Schnittstelle auf der Datenebene bereitzustellen. Wir verwenden ASP.NET MVC 4, um die HTML-Seiten zu rendern, und Knockout.js plus jQuery, um dynamische Interaktionen ohne Seitenladen bereitzustellen.

Zusätzliche Ressourcen: