본문 바로가기

Javascript/Knockout

The "foreach" binding

Purpose(목적)


foreach 바인딩은 Array의 각각의 객체를 위해 마크업의 부분을 복사해서 해당 array item에 마크업을 바인딩한다. 테이블이나 리스트를 렌더링할때 매우 유용하게 사용된다.

여러분의 array가 observable array라고 하면  array에 item을 추가하거나 삭제할때 바인딩은 해당 UI를 효율적으로 변경할 것이다.  마크업 추가 또는 삭제는 다른 DOM요소들의 영향없이 반영된다.

물론 여러분은 if 그리고 with와 같은 control-flow바인딩과 함께 foreach 바인딩을 쓸수 있다.

Example 1: array 반복하기

이 예제는각각의 foreach로 array item에 read-only row를 생성하는 부분입니다.

<table>
    <thead>
        <tr><th>First name</th><th>Last name</th></tr>
    </thead>
    <tbody data-bind="foreach: people">
        <tr>
            <td data-bind="text: firstName"></td>
            <td data-bind="text: lastName"></td>
        </tr>
    </tbody>
</table>
 
<script type="text/javascript">
    ko.applyBindings({
        people: [
            { firstName: 'Bert', lastName: 'Bertington' },
            { firstName: 'Charles', lastName: 'Charlesforth' },
            { firstName: 'Denise', lastName: 'Dentiste' }
        ]
    });
</script>

Example 2: 삭제 추가 예제

다음 예제는 여러분의 array가 observable일 경우면 array의 변경에맞게 UI를 동기화 해줍니다.

People

  • Name at position 0Bert Remove
  • Name at position 1Charles Remove
  • Name at position 2Denise Remove

Source code: View

<h4>People</h4>
<ul data-bind="foreach: people">
    <li>
        Name at position <span data-bind="text: $index"> </span>:
        <span data-bind="text: name"> </span>
        <a href="#" data-bind="click: $parent.removePerson">Remove</a>
    </li>
</ul>
<button data-bind="click: addPerson">Add</button>

Source code: View model

function AppViewModel() {
    var self = this;
 
    self.people = ko.observableArray([
        { name: 'Bert' },
        { name: 'Charles' },
        { name: 'Denise' }
    ]);
 
    self.addPerson = function() {
        self.people.push({ name: "New at " + new Date() });
    };
 
    self.removePerson = function() {
        self.people.remove(this);
    }
}
 
ko.applyBindings(new AppViewModel());

Parameters

  • Main parameter(주 파라미터)

    반복하고 싶은 array를 넘깁니다. 바인딩은 각각의 아이템에 마크업의 부분을 결과로 보여질 것입니다.

    다른방법으로 여러분이 반복하고 싶은 array Javascript 객체의 문자를 data프로퍼티와 함께 전달합니다. 객체의 문자는 afterAdd 와 includeDestoryed를 포함합니다. 그이외의 파라미터는 아래를 참고하십시오.

    만약 array가 observable이라면 foreach 바인딩은 앞으로 일어날 추가 또는 삭제에 대해 DOM의 어떤 부분의 마크업을 렌더링 할것입니다.

  • Additional parameters(추가 파라미터)

    • None(없음)

Note 1: $data로 array 값들 참조하기

위의 예제와 같이 foreah블록 안에서 바인딩은 각각의 array 아이템의 프로퍼티를 참조할수 있습니다. 예를 들면 Example1은 firstNamelastName의 속성을 참조하고 있습니다.

만약 여러분이 array의 엔트리 자체를 참조하기 원한다면? 이러한 경우 여러분은 $data라는 특별한 컨텍스트 속성을 사용할수 있습니다.  foreach블록 안에서 지금 진행중인 아이템을 나타냅니다. 예를 들면,

<ul data-bind="foreach: months">
    <li>
        The current item is: <b data-bind="text: $data"></b>
    </li>
</ul>
 
<script type="text/javascript">
    ko.applyBindings({
        months: [ 'Jan', 'Feb', 'Mar', 'etc' ]
    });
</script>

만약 여러분이 각각의 entry의 프로퍼티를 접근할때 $data를 접두어로 사용할 수있습니다. 예를들어 Example 1을 아래와 같이 다시 작성할수 있습니다.:

<td data-bind="text: $data.firstName"></td>

그러나 여러분은 그럴필요가 없습니다. 왜냐면 firstname은 기본적으로 $data 문맥안에 있으니까요.

Note 2: $index, $parent 그리고 다른 context 속성 사용하기

Example2에서 본것처럼 $index를 상요하여 현재 array item의 index를 참조할수 있습니다. $index 는 observable이고 만약 item의 index가 변경이 되면 자동적으로 업데이트 됩니다.

유사하게 여러분은 $parent를 사용하여 foreach블록 밖에 데이터를 참조할수 잇습니다.:

<h1 data-bind="text: blogPostTitle"></h1>
<ul data-bind="foreach: likes">
    <li>
        <b data-bind="text: name"></b> likes the blog post <b data-bind="text: $parent.blogPostTitle"></b>
    </li>
</ul>

보다 많은 정보를 원하신다면 아래의 링크를 확인하십시오. http://knockoutjs.com/documentation/binding-context.html

Note 3: 컨테이너 요소없이 foreach사용하기

어떠현 경우에 여러분은 특정부분을 반복하여 생성하고 싶을겁니다. 그러나 여러분은 어떤 container 요소들도 필요치 않습니다. 예를 들어 아래와 같이 여려분은 마크업을 생성하기 원한다면:

<ul>
    <li class="header">Header item</li>
    <!-- The following are generated dynamically from an array -->
    <li>Item A</li>
    <li>Item B</li>
    <li>Item C</li>
</ul>

이 예제에서보면 어떤 곳에도 foreach 바인딩을 설정하지 않았습니다. <ul>요소에도 설정할수 없고 <li>요소에도 설정할수 없습니다.

위의 같은 경우 containerless control flow 문법을 주석과 태그와 함께 사용하시면 됩니다.

<ul>
    <li class="header">Header item</li>
    <!-- ko foreach: myItems -->
        <li>Item <span data-bind="text: $data"></span></li>
    <!-- /ko -->
</ul>
 
<script type="text/javascript">
    ko.applyBindings({
        myItems: [ 'A', 'B', 'C' ]
    });
</script>

<!-- ko --> 와 <!-- /ko --> 주석은 스타트와 엔드표시를 나타냅니다. 그리고 안에 마크업을 표시합니다. Knockout은 이러한 문법을 이해하고 마치 실제 컨테이너 안에 요소가 있는것처럼 바인딩을 해줍니다.

Note 4: 기본적으로 파멸된 엔트리들은 숨겨집니다.

어떤 상황에서 여러분은 array의 엔트리를 마치 삭제된것처럼 마크를 하길 원할것입니다. 이때 실제로는 데이터의 삭제없이 할수 있습니다. 이러한 걸 non-destructive delete 라고 합니다. 보다 많은 상세한 내용은 아래를 참고 해주세요 http://knockoutjs.com/documentation/observableArrays.html#destroy_and_destroyall_note_usually_relevant_to_ruby_on_rails_developers_only

기본적으로 foreach 바인딩은 destroyed 마크가 된 엔트르는 넘어 갑니다. 만약 여러분이 destroyed 엔트리가 보여지기 원한다면 includeDestroyed 옵션을 사용하세하십시오. 예를 들면

<div data-bind='foreach: { data: myArray, includeDestroyed: true }'>
    ...
</div>

Note 5: Post-processing or animating the generated DOM elements

여러분이 DOM의 요소를 생성하는데 있어 좀더 커스텀한 로직을 실행하고 싶다면 아래와 같은 caaback들을 사용할수 있습니다.:

  • afterRender — foreach 블록이 document에 복사되거나 추가될때 매번 호출됩니다. 그리고 foreach 가 처음으로 초가화 될때 그리고 새로운 엔트리가 해당 array에 나중에 추가되었을때도 호출됩니다. Knockout은 callback에 다음 파라미터를 허용합니다:

    1. DOM요소에 삽입된 array
    2. 바인딩될 데이터 아이템
  • afterAdd — afterRender 비슷하다, 단지 새로운 엔크리가 array에 추가될 때만 호출된다.다 . 일반적으로 이 callback은 jQuery에  $(domNode).fadeIn() 과 같이 쓰인다. 파라미터들은 아래와같다

    1. document에 추가될 DOM Node
    2. 추가된 array 요소의 Index
    3. 추가된 array요소
  • beforeRemove — array item이 삭제되었을때 호출됩니다. 그러나 DOM node가 삭제되기 전에는 호출 되지 않습니다. 이건 jQuery에 $(domNode).fadeOut() 와 같습니다. 그리고 callback 파라미터들은 아래와 같습니다.:

    1. 삭제해야할 DOM node
    2. 삭제된 array 요소의 index
    3. 삭제된 array 요소

afterRender.를 사용하는 예는 아래와 같습니다. 아래예제는 단순하게 jQuery를 사용해서 요소를 빨간색으로 바꿉니다:

<ul data-bind="foreach: { data: myItems, afterRender: handleAfterRender }">
    <li data-bind="text: $data"></li>
</ul>
 
<script type="text/javascript">
    ko.applyBindings({
        myItems: ko.observableArray([ 'A', 'B', 'C' ]),
        handleAfterRender: function(elements, data) {
            $(elements).css({ color: 'red' });
        }
    });
</script>

afterAdd 와 beforeRemove 를 사용한 예제는 아래를 참고해 주세요.

http://knockoutjs.com/examples/animatedTransitions.html

필요한 라이브러리

Knockout Core library.