다음을 통해 공유


5부: Knockout.js 사용하여 동적 UI 만들기

작성자: Rick Anderson

완료된 프로젝트 다운로드

Knockout.js를 사용하여 동적 UI 만들기

이 섹션에서는 Knockout.js 사용하여 관리 보기에 기능을 추가합니다.

Knockout.js HTML 컨트롤을 데이터에 쉽게 바인딩할 수 있는 Javascript 라이브러리입니다. Knockout.js MVVM(Model-View-ViewModel) 패턴을 사용합니다.

  • 모델은 비즈니스 도메인(이 경우 제품 및 주문)에 있는 데이터의 서버 쪽 표현입니다.
  • 보기는 프레젠테이션 계층(HTML)입니다.
  • 뷰 모델은 모델 데이터를 보유하는 Javascript 개체입니다. 뷰 모델은 UI의 코드 추상화입니다. HTML 표현에 대한 지식이 없습니다. 대신 "항목 목록"과 같은 보기의 추상 기능을 나타냅니다.

뷰는 뷰 모델에 데이터 바인딩됩니다. 뷰 모델에 대한 업데이트 보기에 자동으로 반영됩니다. 또한 view-model은 보기에서 단추 클릭과 같은 이벤트를 가져오고 주문 만들기와 같은 모델에 대한 작업을 수행합니다.

H TML 데이터, 뷰 모델, j son 및 Web API I 컨트롤러 간의 상호 작용 다이어그램

H TML 데이터, 뷰 모델, j son 및 Web API I 컨트롤러 간의 상호 작용을 보여 주는 다이어그램 H TM L 데이터 상자에는 보기라는 레이블이 지정되어 있습니다. 데이터 바인딩 레이블이 지정된 이중 화살표는 H T ML 데이터 상자를 보기 모델 상자에 연결합니다. 서버의 H TT P 요청 및 j son 모델에 레이블이 지정된 이중 화살표는 뷰 모델을 Web API 컨트롤러에 연결합니다.

먼저 뷰 모델을 정의합니다. 그런 다음 HTML 태그를 view-model에 바인딩합니다.

다음 Razor 섹션을 관리.cshtml에 추가합니다.

@section Scripts {
  @Scripts.Render("~/bundles/jqueryval")
  <script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.1.0.js")"></script> 
  <script type="text/javascript">
  // View-model will go here
  </script>
}

파일의 아무 곳이나 이 섹션을 추가할 수 있습니다. 보기가 렌더링되면 섹션이 닫는 </본문> 태그 바로 앞의 HTML 페이지 아래쪽에 나타납니다.

이 페이지의 모든 스크립트는 주석으로 표시된 스크립트 태그 내부로 이동합니다.

<script type="text/javascript">
  // View-model will go here
  </script>

먼저 뷰 모델 클래스를 정의합니다.

function ProductsViewModel() {
    var self = this;
    self.products = ko.observableArray();
}

ko.observableArray관찰 가능한 개체라고 하는 녹아웃의 특수한 종류의 개체입니다. Knockout.js 설명서에서 관찰 가능 항목은 "구독자에게 변경 내용을 알릴 수 있는 JavaScript 개체"입니다. 관찰 가능한 변경 내용이 변경되면 보기가 일치하도록 자동으로 업데이트됩니다.

배열을 products 채우려면 웹 API에 AJAX 요청을 합니다. 뷰 모음에 API에 대한 기본 URI를 저장했습니다(자습서의 4부 참조).

function ProductsViewModel() {
    var self = this;
    self.products = ko.observableArray();

    // New code
    var baseUri = '@ViewBag.ApiUrl';
    $.getJSON(baseUri, self.products);
}

다음으로, 뷰 모델에 함수를 추가하여 제품을 만들고, 업데이트하고, 삭제합니다. 이러한 함수는 웹 API에 AJAX 호출을 제출하고 결과를 사용하여 뷰 모델을 업데이트합니다.

function ProductsViewModel() {
    var self = this;
    self.products = ko.observableArray();

    var baseUri = '@ViewBag.ApiUrl';

    // New code
    self.create = function (formElement) {
        // If the form data is valid, post the serialized form data to the web API.
        $(formElement).validate();
        if ($(formElement).valid()) {
            $.post(baseUri, $(formElement).serialize(), null, "json")
                .done(function (o) { 
                    // Add the new product to the view-model.
                    self.products.push(o); 
                });
        }
    }

    self.update = function (product) {
        $.ajax({ type: "PUT", url: baseUri + '/' + product.Id, data: product });
    }

    self.remove = function (product) {
        // First remove from the server, then from the view-model.
        $.ajax({ type: "DELETE", url: baseUri + '/' + product.Id })
            .done(function () { self.products.remove(product); });
    }

    $.getJSON(baseUri, self.products);
}

이제 가장 중요한 부분: DOM이 가득 차면 ko.applyBindings 함수를 호출하고 의 ProductsViewModel새 instance 전달합니다.

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

ko.applyBindings 메서드는 Knockout을 활성화하고 뷰 모델을 보기에 연결합니다.

이제 뷰 모델이 있으므로 바인딩을 만들 수 있습니다. Knockout.js HTML 요소에 특성을 추가하여 data-bind 이 작업을 수행합니다. 예를 들어 HTML 목록을 배열에 바인딩하려면 바인딩을 foreach 사용합니다.

<ul id="update-products" data-bind="foreach: products">

바인딩은 foreach 배열을 반복하고 배열의 각 개체에 대한 자식 요소를 만듭니다. 자식 요소의 바인딩은 배열 개체의 속성을 참조할 수 있습니다.

"update-products" 목록에 다음 바인딩을 추가합니다.

<ul id="update-products" data-bind="foreach: products">
    <li>
        <div>
            <div class="item">Product ID</div> <span data-bind="text: $data.Id"></span>
        </div>
        <div>
            <div class="item">Name</div> 
            <input type="text" data-bind="value: $data.Name"/>
        </div> 
        <div>
            <div class="item">Price ($)</div> 
            <input type="text" data-bind="value: $data.Price"/>
        </div>
        <div>
            <div class="item">Actual Cost ($)</div> 
            <input type="text" data-bind="value: $data.ActualCost"/>
        </div>
        <div>
            <input type="button" value="Update" data-bind="click: $root.update"/>
            <input type="button" value="Delete Item" data-bind="click: $root.remove"/>
        </div>
    </li>
</ul>

요소는 <li>foreach 바인딩의 scope 내에서 발생합니다. 즉, Knockout은 배열의 각 제품에 대해 요소를 한 번 렌더링합니다 products . 요소 내 <li> 의 모든 바인딩은 해당 제품 instance 참조합니다. 예를 들어 는 $data.Name 제품의 속성을 참조 Name 합니다.

텍스트 입력의 값을 설정하려면 바인딩을 value 사용합니다. 단추는 바인딩을 사용하여 모델 뷰의 함수에 click 바인딩됩니다. 제품 instance 각 함수에 매개 변수로 전달됩니다. 자세한 내용은 Knockout.js 설명서 에 다양한 바인딩에 대한 설명이 있습니다.

다음으로, 제품 추가 양식에서 제출 이벤트에 대한 바인딩을 추가합니다.

<form id="addProduct" data-bind="submit: create">

이 바인딩은 create 뷰 모델에서 함수를 호출하여 새 제품을 만듭니다.

관리 보기에 대한 전체 코드는 다음과 같습니다.

@model ProductStore.Models.Product

@{
    ViewBag.Title = "Admin";
}

@section Scripts {
  @Scripts.Render("~/bundles/jqueryval")
  <script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.0.0.js")"></script> 
  <script type="text/javascript">
      function ProductsViewModel() {
          var self = this;
          self.products = ko.observableArray();

          var baseUri = '@ViewBag.ApiUrl';

          self.create = function (formElement) {
              // If valid, post the serialized form data to the web api
              $(formElement).validate();
              if ($(formElement).valid()) {
                  $.post(baseUri, $(formElement).serialize(), null, "json")
                      .done(function (o) { self.products.push(o); });
              }
          }

          self.update = function (product) {
              $.ajax({ type: "PUT", url: baseUri + '/' + product.Id, data: product });
          }

          self.remove = function (product) {
              // First remove from the server, then from the UI
              $.ajax({ type: "DELETE", url: baseUri + '/' + product.Id })
                  .done(function () { self.products.remove(product); });
          }

          $.getJSON(baseUri, self.products);
      }

      $(document).ready(function () {
          ko.applyBindings(new ProductsViewModel());
      })
  </script>
}

<h2>Admin</h2>
<div class="content">
    <div class="float-left">
    <ul id="update-products" data-bind="foreach: products">
        <li>
            <div>
                <div class="item">Product ID</div> <span data-bind="text: $data.Id"></span>
            </div>
            <div>
                <div class="item">Name</div> 
                <input type="text" data-bind="value: $data.Name"/>
            </div> 
            <div>
                <div class="item">Price ($)</div> 
                <input type="text" data-bind="value: $data.Price"/>
            </div>
            <div>
                <div class="item">Actual Cost ($)</div> 
                <input type="text" data-bind="value: $data.ActualCost"/>
            </div>
            <div>
                <input type="button" value="Update" data-bind="click: $root.update"/>
                <input type="button" value="Delete Item" data-bind="click: $root.remove"/>
            </div>
        </li>
    </ul>
    </div>

    <div class="float-right">
    <h2>Add New Product</h2>
    <form id="addProduct" data-bind="submit: create">
        @Html.ValidationSummary(true)
        <fieldset>
            <legend>Contact</legend>
            @Html.EditorForModel()
            <p>
                <input type="submit" value="Save" />
            </p>
        </fieldset>
    </form>
    </div>
</div>

애플리케이션을 실행하고 관리자 계정으로 로그인한 다음 "관리" 링크를 클릭합니다. 제품 목록이 표시되고 제품을 생성, 업데이트 또는 삭제할 수 있어야 합니다.