Handlebars  코딩 해보기

 

1)    기본적인 구조를 통해 이해

 

Handlebar 템플릿은 아래처럼 script태그 안에 type “text/x-handlebars-template” 등으로 설정하고 위치시킨다. 그리고 템플릿 구조에 {{ }} 감싸진 부분이 데이터가 binding되는 부분이다.

{{#users}} {{/users}} 안에 들어있는 html 태그들은 items라는 배열의 길이만큼 반복하게 된다. 그리고 내부의 {{name}},{{id}},{{email}} 배열 요소 객체의 name,id,email 속성값이 바인딩 된다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<script id="entry-template" type="text/x-handlebars-template">

<table>

    <thead> 

        <th>이름</th> 

        <th>아이디</th> 

        <th>메일주소</th> 

    </thead> 

    <tbody> 

        {{#users}} 

        <tr> 

            <td>{{name}}</td> 

            <td>{{id}}</td> 

            <td><a href="mailto:{{email}}">{{email}}</a></td> 

        </tr> 

        {{/users}} 

    </tbody> 

</table>

</script>

Colored by Color Scripter

cs

 

실제 템플릿과의 바인딩은 자바스크립트를 통해서 이루어진다. 아래는 자바스크립트를 통해 Binding하는 코드이다.

아래 코드를 보면 먼저 앞에서 작성한 Handlebar Template의 내용을 가져온다. Handlebars.compile 메소드를 통해 Template을 컴파일한 뒤, 리턴 된 함수의 Parameter에 바인딩할 데이터를 Parameter로 넣으면 데이터가 BindingHTML Template이 리턴된다. HTML TemplateDOM에 추가하면 끝난다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

//핸들바 템플릿 가져오기

var source = $("#entry-template").html(); 

 

//핸들바 템플릿 컴파일

var template = Handlebars.compile(source); 

 

//핸들바 템플릿에 바인딩할 데이터

var data = {

        users: [

            { name"홍길동1", id: "aaa1", email: "aaa1@gmail.com" },

            { name"홍길동2", id: "aaa2", email: "aaa2@gmail.com" },

            { name"홍길동3", id: "aaa3", email: "aaa3@gmail.com" },

            { name"홍길동4", id: "aaa4", email: "aaa4@gmail.com" },

            { name"홍길동5", id: "aaa5", email: "aaa5@gmail.com" }

        ]

}; 

 

//핸들바 템플릿에 데이터를 바인딩해서 HTML 생성

var html = template(data);

 

//생성된 HTML DOM 주입

$('body').append(html);

Colored by Color Scripter

cs

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

//Handlebar 템플릿을 가져오기

var source = $("#entry-template").html();

//Handlebar 템플릿을 precompile

var template = Handlebars.compile(source);

//Handlebar 템플릿에 바인딩할 데이터

var data = {

items:[

{name"shoes", price:"5000", intro:"www.a.com"},

{name"T-shirt", price:"1000", intro:"www.b.com"},

{name"Jeans", price:"2000", intro:"www.c.com"}

]

};

//Handlebar 템플릿에 데이터를 바인딩해서 HTML 생성

var itemList = template(data);

//생성된 HTML DOM 주입

$('body').append(itemList);

cs

 

아래와 같은 결과가 출력된다.

 

1

2

3

4

5

6

이름    아이디    메일주소

홍길동1    aaa1    aaa1@gmail.com

홍길동2    aaa2    aaa2@gmail.com

홍길동3    aaa3    aaa3@gmail.com

홍길동4    aaa4    aaa4@gmail.com

홍길동5    aaa5    aaa5@gmail.com

cs

 

 

참고로 링크 부분의 malito는 저 링크를 클릭했을 때 바로 전자메일을 보낼 수 있게 해주는 태그이다.

 

코드를 통해 알 수 있듯이 실제 템플릿이 데이터를 컴파일하고, 바인딩해주는 부분이 모두 자바스크립트 코드에서 이루어진다. Handlebars.compile 메서드를 이용해 템플릿을 컴파일하고, 리턴 된 함수의 ParameterBinding된 데이터를 Parameter로 넣으면 Binding HTML템플릿이 리턴 된다. 그리고 이 HTML템플릿을 DOM에 추가함으로써 구현이 완료된다.

 

 

2)    사용자 정의 Helper 사용해보기

 

Handlebar Mustache를 기초로 개발되었지만, Mustache와의 차별 점은 바로 사용자 정의 Helper이다. Mustache는 단순하게 주입된 데이터를 바인딩해주는 템플릿 엔진이었다면 Handlebar if, unless 등의 기본 Helper뿐만 아니라 사용자 정의 Helper를 추가해서 좀 더 템플릿 엔진에서 간단한 로직을 포함시킬 수 있다는 것이다. 아래는 기본적인 사용자 정의 Helper예시이다.

 

1

2

{{!-- 사용자 정의 Helper email id 인자로 넘긴다 --}}

<td><a href="mailto:{{email id}}">{{email id}}</a></td>

cs

 

앞의 예시에서 HTML코드에서  email라고만 되었던 부분에 {{email id}} 형태로 바뀌고, idParameter를 전달해주고 있다. , email이라는 이름의 사용자 정의 Helper가 사용되고 있는걸 알 수 있다. 이를 해석하면 email이라는 이름의 사용자 정의 Helper를 호출하면서 Parameterid 값을 전달한다는 의미이다.

전체 코드를 보면 아래와 같다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<script id="entry-template" type="text/x-handlebars-template">

<table>

    <thead> 

        <th>이름</th> 

        <th>아이디</th> 

        <th>메일주소</th> 

    </thead> 

    <tbody> 

        {{#users}} 

        <tr> 

            <td>{{name}}</td> 

            <td>{{id}}</td> 

            

            {{!-- 사용자 정의 헬퍼인 email id 인자로 넘긴다 --}}

            <td><a href="mailto:{{email id}}">{{email id}}</a></td> 

        </tr> 

        {{/users}} 

    </tbody> 

</table>

</script>

Colored by Color Scripter

cs

 

그리고 {{!--   --}}를 통행 주석을 표시해 주고도 있다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

//핸들바 템플릿 컴파일

var template = Handlebars.compile(source); 

 

//핸들바 템플릿에 바인딩할 데이터

var data = {

        users: [

            { name"홍길동1", id: "aaa1" },

            { name"홍길동2", id: "aaa2" },

            { name"홍길동3", id: "aaa3" },

            { name"홍길동4", id: "aaa4" },

            { name"홍길동5", id: "aaa5" }

        ]

}; 

 

//커스텀 헬퍼 등록 (id 인자로 받아서 전체 이메일 주소를 반환)

Handlebars.registerHelper('email'function (id) {

  return id + "@daum.net";

});

 

//핸들바 템플릿에 데이터를 바인딩해서 HTML 생성

var html = template(data);

 

//생성된 HTML DOM 주입

$('body').append(html);

cs

 

스크립트 부분을 보면 Binding할 데이터에 email이 없는걸 확인할 수 있다. 그 대신 Custom Helper가 등록하는 코드가 구현되고 있는걸 확인할 수 있다. Handlebars.registerHelper라는 메소드를 사용하여 사용자 정의 Helper를 등록하고 있다. 첫번째 ParameterHelper의 이름을 넣고, 두 번째 Parameter에서 Helper의 동작을 정의한다. 위 코드에서는 id을 인자로 받아서 ‘@daum.net’이라는 문자열을 더해주는 로직이다 

결과는 아래와 같다.

 

1

2

3

4

5

6

7

 

이름    아이디    메일주소

홍길동1    aaa1    aaa1@daum.net

홍길동2    aaa2    aaa2@daum.net

홍길동3    aaa3    aaa3@daum.net

홍길동4    aaa4    aaa4@daum.net

홍길동5    aaa5    aaa5@daum.net

cs

 

 

3)    Handlebar에서 제공하는 기본 Helper

 

Handlebar if, unless 등의 기본 Helper와 사용자 정의 Helper를 이용해서 간단한 로직을 구현할 수 있다하지만 if의 경우 오직 true/false만 판별할 수 있기 때문에 복잡한 조건은 Handlebar를 통해서 처리할 수 없다. 사용자 정의 helper를 통해 가능하지만, Temple에 로직을 배제하는 사상과 맞지 않기 때문에 가능하면 사용하지 않는게 좋다.

그럼 Handlebars에서 제공하는 기본 Helper를 알아보자

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

<script id="entry-template" type="text/x-handlebars-template">

<table>

    <thead> 

        <th>이름</th> 

        <th>아이디</th> 

        <th>메일주소</th>

        <th>요소정보</th>

    </thead> 

    <tbody> 

        {{!-- {{#each users}}  {{#users}} 로도 대체 가능하다 --}}

        {{#each users}}

        <tr>

            {{!-- {{name}}  {{this.name}}  같고 {{.}}  현재 name id 포함하고 있는 오브젝트를 가리킨다 --}}

            <td>{{name}}</td> 

            <td>{{id}}</td> 

            

            {{!-- 사용자 정의 헬퍼인 email id 인자로 넘긴다 --}}

            <td><a href="mailto:{{email id}}">{{email id}}</a></td> 

            

            {{!-- 요소의 순번은 @index 혹은 @key 잡을  있는데,

            array object 모두 잡을  있는 key  나아보인다 --}}

            

            {{#if @first}}

                <td> 아이템 ({{@key}} 번째 요소)</td>

            {{else if @last}}

                <td>마지막 아이템 ({{@key}} 번째 요소)</td>

            {{else}}

                <td>중간 아이템 ({{@key}} 번째 요소)</td>

            {{/if}}

        </tr> 

        {{/each}}

    </tbody> 

</table>

</script>

Colored by Color Scripter

cs

 

 

배열 등을 반복해주는 each Helper의 경우에는 #배열명으로 대체가 가능하다. @기호와 함께 몇 번째 인덱스인지도 구분이 가능하다. @first로 첫번째 인덱스를 알 수 있고, @last로 마지막 인덱스를 확인할 수 있다. 또한 해당 인덱스가 몇 번째 인덱스인지, 오브젝트라면 어떤 오브젝트인지 @key를 통해 알 수 있다. 앞에서 설명했듯이 if true/false 만 판별이 가능하며, elseelse if 를 지원하며, unless if의 반대되는 Helper이다.

 

 

4)    partial template 등록 및 사용

 

다른 템플릿엔진처럼 HandlebarHandlebar 템플릿을 다른 Handlebar 템플릿의 일부로 포함시킬 수 잇다. 이를 통해 템플릿의 재 사용성과 가독성을 높일 수 있고, 좀 더 객체지향적인 프로그래밍이 가능하다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

<!-- 핸들바 템플릿 -->

<script id="partial-template" type="text/x-handlebars-template">

    {{!-- #unless 헬퍼는 #if  정반대 기능을 한다--}}

    <h1>리스트 {{#unless users}}<small>사용자 리스트가 없습니다.</small>{{/unless}}</h1>

</script>

 

<!-- 핸들바 템플릿 -->

<script id="entry-template" type="text/x-handlebars-template">

 

{{!-- 조각 템플릿은 #>  사용해서 포함시킬  있다--}}

{{#> commonHeader}}

    partial template 로드 실패시 보여지는 내용

{{/commonHeader}}

 

<table>

    <thead> 

        <th>이름</th> 

        <th>아이디</th> 

        <th>메일주소</th> 

        <th>요소정보</th>

    </thead> 

    <tbody> 

        {{!-- {{#each users}}  {{#users}} 로도 대체 가능하다 --}}

        {{#each users}} 

        <tr> 

            <td>{{name}}</td> 

            <td>{{id}}</td> 

            

            {{!-- 사용자 정의 헬퍼인 email id 인자로 넘긴다 --}}

            <td><a href="mailto:{{email id}}">{{email id}}</a></td> 

            

            {{!-- 요소의 순번은 @index 혹은 @key 잡을  있는데,

            array object 모두 잡을  있는 key  나아보인다 --}}

            

            {{#if @first}}

                <td> 아이템 ({{@key}} 번째 요소)</td>

            {{else if @last}}

                <td>마지막 아이템 ({{@key}} 번째 요소)</td>

            {{else}}

                <td>중간 아이템 ({{@key}} 번째 요소)</td>

            {{/if}}

        </tr> 

        {{/each}}

    </tbody> 

</table>

</script>

Colored by Color Scripter

cs

 

위의 예를 보면, 앞서 나온 예제와는 다른 부분이 있다. Template을 담고 있는 Script 태그가 한 개 더 있다.

 

1

2

3

4

<script id="partial-template" type="text/x-handlebars-template">

{{!-- #unless 헬퍼는 #if  정반대 기능을 한다--}}

<h1>리스트 {{#unless users}}<small>사용자 리스트가 없습니다.</small>{{/unless}}</h1>

</script>

Colored by Color Scripter

cs

 

Entry-template 안을 잘 보면, #> 기호와 함께 partial template을 삽입해 주는 부분을 발견 할 수 있다. 이는 #>와 함께 partial template의 이름을 넣어주면 해당 위치에 partial template이 삽입된다. partial template의 이름은 자바스크립트에서 등록한다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

//핸들바 템플릿 컴파일

var template = Handlebars.compile(source); 

 

//핸들바 템플릿에 바인딩할 데이터

var data = {

        users: [

            { name"홍길동1", id: "aaa1" },

            { name"홍길동2", id: "aaa2" },

            { name"홍길동3", id: "aaa3" },

            { name"홍길동4", id: "aaa4" },

            { name"홍길동5", id: "aaa5" }

        ]

}; 

 

//조각 템플릿을 'commonHeader' 라는 이름으로 등록

Handlebars.registerPartial('commonHeader', partial);

 

//커스텀 헬퍼 등록 (id 인자로 받아서 전체 이메일 주소를 반환)

Handlebars.registerHelper('email'function (id) {

  return id + "@daum.net";

});

 

//핸들바 템플릿에 데이터를 바인딩해서 HTML 생성

var html = template(data);

 

//생성된 HTML DOM 주입

$('body').append(html);

cs

 

위 코드를 보면, entry-template 과 마찬가지로 partial-template을 가져온 뒤, Handlebars.registerPartial 메소드를 사용해서 가져온 TemplatecommonHeader라는 이름으로 등록해주고 있는 것을 확인할 수 있다. 이렇게 등록만 해주면 데이터를 Binding해주는 시점에서 partial template을 삽입해주게 되고, partial template에도 주어진 데이터와 Binding될 부분이 있다면 데이터 Binding역시 처리되게 된다.

 

 

5)    withas 그리고 상대 경로 참조


지금까지 살펴본 내용들은 기본적인 Handlebars의 문법이었다면, 이런 문법을 조합한 좀더 복잡한 구조를 살펴보자. 자주 있는 상황은 아니지만, 이중 혹은 삼중의 Loop을 돌리는 상황에서 상위 Loop의 값을 하위 Loop에서 참조해야 하는 상황에서 활용할 수 있다.

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

<!-- 핸들바 템플릿 -->

<script id="entry-template" type="text/x-handlebars-template">

 

    <table>

        <thead> 

            <th>이름</th> 

            <th>아이디</th> 

            <th>취미</th>

        </thead> 

        <tbody> 

            {{!-- {{#each users}}  {{#users}} 로도 대체 가능하다 --}}

            {{#each users as |user userId|}} 

                <tr> 

                    <td>{{name}}</td> 

                    <td>{{id}}</td> 

                    <td>

                      {{#each hobbys as |hobby hobbyId|}}

                        {{!-- 처음이 아닌 경우에는 쉼표(,) 넣기 --}}

                        {{#unless @first}}, {{/unless}}

 

                                                {{!-- 상위 이터레이션의 인덱스 넘버를 가져올  --}}

                                                {{@../index}} ==

                        {{!-- 상위 이터레이션의 인덱스 넘버는 아래와 같은 방식도 가능하다 --}}

                        {{userId}}

 

                        {{!-- 상대경로로 참조한 name  myName 이라는 변수로 할당 --}}

                        {{#with ../this.name as |myName|}}

                          {{!-- 상대경로를 참조해서 #hobby 현재값 출력 --}}

                          {{myName}}  {{hobbyId}} 취미 {{hobby}}

                        {{/with}}

                      {{/each}}

                    </td>

                </tr> 

            {{/each}}

        </tbody> 

    </table>

 

</script>

Colored by Color Scripter

cs

 

../ 를 사용해서 상위의 경로를 참조할 수 있고, with as 를 활용해서 이렇게 참조한 상위의 값을 다른 이름으로 할당해서 사용하고 있다.

상위 Loop에서 참조하고 있는 user item에 있는 name myName으로 할당하여 활용하고 있다. 그리고 상대 경로를 참조하여 hobby의 값도 출력해주고 있다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

//핸들바 템플릿 가져오기

var source = $("#entry-template").html();

 

//핸들바 템플릿 컴파일

var template = Handlebars.compile(source); 

 

//핸들바 템플릿에 바인딩할 데이터

var data = {

        users: [

            { name"홍길동", id: "aaa", hobbys: ['축구''야구''농구'] },

            { name"이순신", id: "bbb", hobbys: ['족구''피구''탁구'] },

            { name"이성계", id: "ccc", hobbys: ['수구''배구''농구'] },

            { name"장영실", id: "ddd", hobbys: ['축구''피구''농구'] },

            { name"장보고", id: "eee", hobbys: ['배구''야구''족구'] }

        ]

}; 

 

//핸들바 템플릿에 데이터를 바인딩해서 HTML 생성

var html = template(data);

 

//생성된 HTML DOM 주입

$('body').append(html);

Colored by Color Scripter

cs

 

결과는 아래와 같다.

1

2

3

4

5

6

이름    아이디    취미

홍길동    aaa    0 == 0 홍길동  0 취미 축구 , 0 == 0 홍길동  1 취미 야구 , 0 == 0 홍길동  2 취미 농구

이순신    bbb    1 == 1 이순신  0 취미 족구 , 1 == 1 이순신  1 취미 피구 , 1 == 1 이순신  2 취미 탁구

이성계    ccc    2 == 2 이성계  0 취미 수구 , 2 == 2 이성계  1 취미 배구 , 2 == 2 이성계  2 취미 농구

장영실    ddd    3 == 3 장영실  0 취미 축구 , 3 == 3 장영실  1 취미 피구 , 3 == 3 장영실  2 취미 농구

장보고    eee    4 == 4 장보고  0 취미 배구 , 4 == 4 장보고  1 취미 야구 , 4 == 4 장보고  2 취미 족구

cs

 

 

6)    lookup을 활용한 변수 참조


 lookup Helper를 활용하면 특정 상대 경로에 있는 변수 값을 참조할 수 있다. lookup Helper로 참조할 수 있는 변수 값은 with as 를 활용하는 방법으로 거의 대부분 참조 가능하다. 개인적으로는 with as 를 활용하는 것이 더 명시적이기 때문에 선호한다.

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

<!-- 핸들바 템플릿 -->

<script id="entry-template" type="text/x-handlebars-template">

 

    <table>

        <thead> 

            <th>이름</th> 

            <th>아이디</th> 

            <th>취미</th>

        </thead> 

        <tbody> 

            {{!-- {{#each users}}  {{#users}} 로도 대체 가능하다 --}}

            {{#each users as |user userId|}} 

                <tr> 

                    <td>{{name}}</td> 

                    <td>{{id}}</td> 

                    <td>

                      {{#each hobbys as |hobby hobbyId|}}

                          {{!-- 

                                                    상대경로를 참조해서 상위 이터레이션의 name 값을 가져오는 것은

                          with 헬퍼를 사용해서 {{#with ../this.name as |myName|}}

                           같이 처리해줄 수도 있고 아래와 같이

                                                    lookup 활용해서 처리해줄 수도 있다.

                                                --}}

                        {{lookup ../this "name"}}  {{hobbyId}} 취미 {{hobby}}

                      {{/each}}

                    </td>

                </tr> 

            {{/each}}

        </tbody> 

    </table>

 

</script>

Colored by Color Scripter

cs

 

Lookup을 통해 상대 경로에  name값을 찾아서 출력해주고 있다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

//핸들바 템플릿 가져오기

var source = $("#entry-template").html();

 

//핸들바 템플릿 컴파일

var template = Handlebars.compile(source); 

 

//핸들바 템플릿에 바인딩할 데이터

var data = {

        users: [

            { name"홍길동", id: "aaa", hobbys: ['축구''야구''농구'] },

            { name"이순신", id: "bbb", hobbys: ['족구''피구''탁구'] },

            { name"이성계", id: "ccc", hobbys: ['수구''배구''농구'] },

            { name"장영실", id: "ddd", hobbys: ['축구''피구''농구'] },

            { name"장보고", id: "eee", hobbys: ['배구''야구''족구'] }

        ]

}; 

 

//핸들바 템플릿에 데이터를 바인딩해서 HTML 생성

var html = template(data);

 

//생성된 HTML DOM 주입

$('body').append(html);

Colored by Color Scripter

cs

 

 

1

2

3

4

5

6

이름    아이디    취미

홍길동    aaa    홍길동  0 취미 축구 홍길동  1 취미 야구 홍길동  2 취미 농구

이순신    bbb    이순신  0 취미 족구 이순신  1 취미 피구 이순신  2 취미 탁구

이성계    ccc    이성계  0 취미 수구 이성계  1 취미 배구 이성계  2 취미 농구

장영실    ddd    장영실  0 취미 축구 장영실  1 취미 피구 장영실  2 취미 농구

장보고    eee    장보고  0 취미 배구 장보고  1 취미 야구 장보고  2 취미 족구

cs

 

 

2.    Handlebar의 장점

 

  • precompile할 수 있기 때문에 성능개선에 도움이 된다.

  • Helper를 자유롭게 추가할 수 있다.

  • JADE와 같은 문법에 비해 친숙하면서도 가독성이 높다.

  • Grunt 등으로 빌드 자동화에 precompile 과정을 포함시키기 쉽다.

  • 템플릿에는 로직 코드를 넣지 않는 것이 일반적이다.

    • 컴파일한 템플릿에서 오류가 발생했을 때 디버깅도 어렵다.

    • 실제 문법에서도 간단한 분기문, 배열, 반복문 정도를 지원한다.

 


 

참고사이트

 

페이지: http://handlebarsjs.com/

깃허브: https://github.com/wycats/handlebars.js/

http://ohgyun.com/427

http://sailboat-d.tistory.com/40

http://jojoldu.tistory.com/23

http://tmondev.blog.me/220398995882

http://programmingsummaries.tistory.com/381

https://blog.outsider.ne.kr/939

http://aroundck.tistory.com/957

http://uncle-bae.blogspot.kr/2016/06/handlebars-expression.html


'IT > Handlebar' 카테고리의 다른 글

Handlebar란  (0) 2017.01.12

+ Recent posts