Bagikan melalui


Bagian 7: Membuat Halaman Utama

oleh Rick Anderson

Unduh Proyek yang Selesai

Membuat Halaman Utama

Di bagian ini, Anda akan membuat halaman aplikasi utama. Halaman ini akan lebih kompleks daripada halaman Admin, jadi kami akan mendekatinya dalam beberapa langkah. Sepanjang jalan, Anda akan melihat beberapa teknik Knockout.js yang lebih canggih. Berikut adalah tata letak dasar halaman:

Diagram interaksi antara produk, kelir, pesanan, dan elemen detail pesanan halaman utama.

Diagram interaksi antara produk, kelir, pesanan, dan elemen detail pesanan halaman utama. Elemen produk diberi label GET A P I / products dengan panah yang menunjuk ke elemen item. Elemen item tersambung ke elemen pesanan oleh panah berlabel POST A P I/orders. Elemen pesanan terhubung ke elemen detail dengan panah berlabel GET A P I/orders. Elemen detail adalah lebeled GET A P I / orders / i d.

  • "Produk" menyimpan berbagai produk.
  • "Ke cart" menyimpan berbagai produk dengan jumlah. Mengeklik "Tambahkan ke Kemudi" memperbarui ke cart.
  • "Pesanan" menyimpan array ID pesanan.
  • "Detail" menyimpan detail pesanan, yang merupakan array item (produk dengan jumlah)

Kita akan mulai dengan mendefinisikan beberapa tata letak dasar dalam HTML, tanpa pengikatan data atau skrip. Buka file Views/Home/Index.cshtml dan ganti semua konten dengan yang berikut ini:

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

Selanjutnya, tambahkan bagian Skrip dan buat view-model kosong:

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

Berdasarkan desain yang dibuat sketsa sebelumnya, model tampilan kami membutuhkan pengamatan untuk produk, ke cart, pesanan, dan detail. Tambahkan variabel berikut ke AppViewModel objek :

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

Pengguna dapat menambahkan item dari daftar produk ke dalam ke cart, dan menghapus item dari ke cart. Untuk merangkum fungsi-fungsi ini, kita akan membuat kelas model tampilan lain yang mewakili produk. Tambahkan kode berikut ke AppViewModel:

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

Kelas ProductViewModel ini berisi dua fungsi yang digunakan untuk memindahkan produk ke dan dari ke cart: addItemToCart menambahkan satu unit produk ke ke cart, dan removeAllFromCart menghapus semua jumlah produk.

Pengguna dapat memilih pesanan yang ada dan mendapatkan detail pesanan. Kami akan merangkum fungsionalitas ini ke dalam model tampilan lain:

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

diinisialisasi OrderDetailsViewModel dengan pesanan, dan mengambil detail pesanan dengan mengirim permintaan AJAX ke server.

Selain itu total , perhatikan properti pada OrderDetailsViewModel. Properti ini adalah jenis khusus yang dapat diamati yang disebut komputasi yang dapat diamati. Sesuai namanya, komputasi yang dapat diamati memungkinkan Anda mengikat data ke nilai komputasi—dalam hal ini, total biaya pesanan.

Selanjutnya, tambahkan fungsi-fungsi ini ke AppViewModel:

  • resetCart menghapus semua item dari kemudi.
  • getDetails mendapatkan detail untuk pesanan (dengan mendorong yang baru OrderDetailsViewModel ke details dalam daftar).
  • createOrder menciptakan urutan baru dan mengikat keranjang.
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);
            }  
        });
    };
};

Terakhir, inisialisasi model tampilan dengan membuat permintaan AJAX untuk produk dan pesanan:

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, itu banyak kode, tapi kami membangunnya langkah demi langkah, jadi mudah-mudahan desainnya jelas. Sekarang kita dapat menambahkan beberapa Knockout.js pengikatan ke HTML.

Produk

Berikut adalah pengikatan untuk daftar produk:

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

Ini melakukan iterasi atas array produk dan menampilkan nama dan harga. Tombol "Tambahkan ke Pesanan" hanya terlihat saat pengguna masuk.

Tombol "Tambahkan ke Pesanan" memanggil instans addItemToCartProductViewModel untuk produk. Ini menunjukkan fitur Knockout.js yang bagus: Saat model tampilan berisi model tampilan lainnya, Anda dapat menerapkan pengikatan ke model dalam. Dalam contoh ini, pengikatan dalam foreach diterapkan ke setiap ProductViewModel instans. Pendekatan ini jauh lebih bersih daripada menempatkan semua fungsionalitas ke dalam satu model tampilan.

Keranjang

Berikut adalah pengikatan untuk keliru:

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

Ini mengulangi array keranjang dan menampilkan nama, harga, dan kuantitas. Perhatikan bahwa tautan "Hapus" dan tombol "Buat Pesanan" terikat ke fungsi model tampilan.

Pesanan

Berikut adalah pengikatan untuk daftar pesanan:

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

Ini melakukan iterasi atas pesanan dan menunjukkan ID pesanan. Peristiwa klik pada tautan terikat ke getDetails fungsi.

Detail Pesanan

Berikut adalah pengikatan untuk detail pesanan:

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

Ini mengulangi item dalam urutan dan menampilkan produk, harga, dan kuantitas. Div sekitarnya hanya terlihat jika array detail berisi satu atau beberapa item.

Kesimpulan

Dalam tutorial ini, Anda membuat aplikasi yang menggunakan Kerangka Kerja Entitas untuk berkomunikasi dengan database, dan ASP.NET Web API untuk menyediakan antarmuka yang menghadap publik di atas lapisan data. Kami menggunakan ASP.NET MVC 4 untuk merender halaman HTML, dan Knockout.js ditambah jQuery untuk menyediakan interaksi dinamis tanpa memuat ulang halaman.

Sumber daya tambahan: