7. Bölüm: Ana sayfa oluşturmaPart 7: Creating the Main Page

, Mike te sonby Mike Wasson

Tamamlanmış projeyi indirDownload Completed Project

Ana Sayfayı OluşturmaCreating the Main Page

Bu bölümde, ana uygulama sayfası oluşturacaksınız.In this section, you will create the main application page. Bu sayfa, yönetici sayfasından daha karmaşık olacaktır, bu nedenle bunu çeşitli adımlarda yaklaşıyoruz.This page will be more complex than the Admin page, so we'll approach it in several steps. Bu şekilde, daha gelişmiş altını gizleme. js tekniklerini görürsünüz.Along the way, you'll see some more advanced Knockout.js techniques. Sayfanın temel düzeni aşağıda verilmiştir:Here is the basic layout of the page:

  • "Ürünler" bir ürün dizisini tutar."Products" holds an array of products.
  • "Sepet" miktarları olan bir ürün dizisini tutar."Cart" holds an array of products with quantities. "Sepete Ekle" seçeneğine tıkladığınızda sepette güncelleştirme yapılır.Clicking "Add to Cart" updates the cart.
  • "Siparişler" bir sıra kimliği dizisi içerir."Orders" holds an array of order IDs.
  • "Ayrıntılar", bir dizi öğe olan (miktarları olan ürünler) bir sıra ayrıntısı tutar"Details" holds an order detail, which is an array of items (products with quantities)

HTML 'de veri bağlama veya betik olmadan bazı temel düzenleri tanımlayarak başlayacağız.We'll start by defining some basic layout in HTML, with no data binding or script. Views/Home/Index. cshtml dosyasını açın ve tüm içeriği şu şekilde değiştirin:Open the file Views/Home/Index.cshtml and replace all of the contents with the following:

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

Sonra, bir komut dosyası bölümü ekleyin ve boş bir görünüm modeli oluşturun:Next, add a Scripts section and create an empty 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>
}

Daha önce tasarım taslağı temel alınarak, görünüm modeliniz ürünler, sepet, siparişler ve Ayrıntılar için gözlemlenenler gerektirir.Based on the design sketched earlier, our view model needs observables for products, cart, orders, and details. AppViewModel nesnesine aşağıdaki değişkenleri ekleyin:Add the following variables to the AppViewModel object:

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

Kullanıcılar ürünler listesinden sepete öğeler ekleyebilir ve sepetten öğeleri kaldırabilir.Users can add items from the products list into the cart, and remove items from the cart. Bu işlevleri kapsüllemek için, bir ürünü temsil eden başka bir görünüm modeli sınıfı oluşturacağız.To encapsulate these functions, we'll create another view-model class that represents a product. Aşağıdaki kodu AppViewModelekleyin:Add the following code to 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);
        };
    }
}

ProductViewModel sınıfı, ürünü sepet içine ve sepetinden taşımak için kullanılan iki işlevi içerir: addItemToCart bir ürünün bir birimini sepete ekler ve removeAllFromCart ürünün tüm miktarlarını kaldırır.The ProductViewModel class contains two functions that are used to move the product to and from the cart: addItemToCart adds one unit of the product to the cart, and removeAllFromCart removes all quantities of the product.

Kullanıcılar mevcut bir siparişi seçebilir ve sipariş ayrıntılarını alabilir.Users can select an existing order and get the order details. Bu işlevi başka bir görünüm modelinde kapsülliyoruz:We'll encapsulate this functionality into another view-model:

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

OrderDetailsViewModel bir siparişle başlatılır ve sunucuya bir AJAX isteği göndererek sipariş ayrıntılarını getirir.The OrderDetailsViewModel is initialized with an order, and it fetches the order details by sending an AJAX request to the server.

Ayrıca, OrderDetailsViewModel``total özelliğine de dikkat edin.Also, notice the total property on the OrderDetailsViewModel. Bu özellik, hesaplanan observableadlı özel bir observable türüdür.This property is a special kind of observable called a computed observable. Adından da anlaşılacağı gibi, hesaplanan bir observable, bu durumda, siparişin toplam maliyeti olan—bir hesaplanan değere veri bağlamanıza olanak tanır.As the name implies, a computed observable lets you data bind to a computed value—in this case, the total cost of the order.

Sonra şu işlevleri AppViewModelekleyin:Next, add these functions to AppViewModel:

  • resetCart tüm öğeleri sepetten kaldırır.resetCart removes all items from the cart.
  • getDetails bir siparişin ayrıntılarını alır (details listesine yeni bir OrderDetailsViewModel göndererek).getDetails gets the details for an order (by pushing a new OrderDetailsViewModel onto the details list).
  • createOrder yeni bir sipariş oluşturur ve sepeti boşaltır.createOrder creates a new order and empties the cart.
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);
            }  
        });
    };
};

Son olarak, ürünler ve siparişler için AJAX istekleri yaparak görünüm modelini başlatın:Finally, initialize the view model by making AJAX requests for the products and orders:

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

Daha fazla kod olan Tamam, ancak adım adım bir adım geliştirdik, bu sayede tasarımın açık olması gerekir.OK, that's a lot of code, but we built it up step-by-step, so hopefully the design is clear. Artık HTML 'ye bazı altını gizleme. js bağlamaları ekleyebiliriz.Now we can add some Knockout.js bindings to the HTML.

ÜrünlerProducts

Ürün listesinin bağlamaları aşağıda verilmiştir:Here are the bindings for the product list:

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

Bu, Products dizisinin üzerinde dolaşır ve adı ve fiyatı görüntüler.This iterates over the products array and displays the name and price. "Sıraya ekle" düğmesi yalnızca Kullanıcı oturum açtığında görünür.The "Add to Order" button is visible only when the user is logged in.

"Sıraya ekle" düğmesi, ürünün ProductViewModel örneğindeki addItemToCart çağırır.The "Add to Order" button calls addItemToCart on the ProductViewModel instance for the product. Bu, altını gizleme. js ' nin iyi bir özelliğini gösterir: bir görünüm modeli diğer görünüm modellerini içerdiğinde, bağlamaları iç modele uygulayabilirsiniz.This demonstrates a nice feature of Knockout.js: When a view-model contains other view-models, you can apply the bindings to the inner model. Bu örnekte, foreach içindeki bağlamalar ProductViewModel örneklerinin her birine uygulanır.In this example, the bindings within the foreach are applied to each of the ProductViewModel instances. Bu yaklaşım, tüm işlevleri tek bir görünüm modeline yerleştirmekten çok daha temizdir.This approach is much cleaner than putting all of the functionality into a single view-model.

TinCart

Sepetin bağlamaları aşağıda verilmiştir:Here are the bindings for the cart:

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

Bu, sepet dizisinin üzerinde dolaşır ve adı, fiyatı ve miktarı görüntüler.This iterates over the cart array and displays the name, price, and quantity. "Kaldır" bağlantısının ve "sipariş oluştur" düğmesinin görünüm-model işlevlerine bağlandığını unutmayın.Note that the "Remove" link and the "Create Order" button are bound to view-model functions.

SiparişlerineOrders

Siparişler listesinin bağlamaları aşağıda verilmiştir:Here are the bindings for the orders list:

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

Bu, siparişlerin üzerinde dolaşır ve sipariş KIMLIĞINI gösterir.This iterates over the orders and shows the order ID. Bağlantıdaki tıklama olayı getDetails işlevine bağlıdır.The click event on the link is bound to the getDetails function.

Sipariş AyrıntılarıOrder Details

Sıra ayrıntılarının bağlamaları aşağıda verilmiştir:Here are the bindings for the order details:

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

Bu, siparişteki öğeleri yineler ve ürünü, fiyatı ve miktarı görüntüler.This iterates over the items in the order and displays the product, price, and quantity. Çevreleyen div yalnızca details dizisi bir veya daha fazla öğe içeriyorsa görünür.The surrounding div is visible only if the details array contains one or more items.

SonuçConclusion

Bu öğreticide, veritabanıyla iletişim kurmak için Entity Framework kullanan bir uygulama oluşturdunuz ve veri katmanının en üstünde herkese açık bir arabirim sağlamak için ASP.NET Web API 'SI.In this tutorial, you created an application that uses Entity Framework to communicate with the database, and ASP.NET Web API to provide a public-facing interface on top of the data layer. HTML sayfalarını işlemek için ASP.NET MVC 4, sayfa yeniden yüklemeye gerek kalmadan dinamik etkileşimler sağlamak için de altını gizleme. js ' yi kullanırız.We use ASP.NET MVC 4 to render the HTML pages, and Knockout.js plus jQuery to provide dynamic interactions without page reloads.

Ek kaynaklar:Additional resources: