ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Svelte] Svelte 기초 - Svelte로 Form 다루기 / Custom Event Dispatch하기
    Frontend 2020. 6. 21. 21:01

    Form 다루기

    이제 svelte에서 input 요소들을 어떻게 다루는 지 살펴보도록 하자.

     

     

    - Input Text

    - AddPersonForm.svelte

    <script>
      let name;
      let hairColor;
      let age;
    
      const handleSubmit = () => {
        console.log(name, hairColor, age);
      };
    </script>
    
    <h3>Add a new person</h3>
    <form on:submit|preventDefault={handleSubmit}>
      <input type="text" placeholder="name" bind:value={name} />
      <input type="text" placeholder="hair color" bind:value={hairColor} />
      <input type="number" placeholder="age" bind:value={age} />
      <button>Add Person</button>
    </form>

     

    먼저 form 태그에 3가지 input 태그를 만들고 각 input에 변수를 binding했다.

    그리고 handleSubmit 함수를 form 태그에 submit 이벤트로 등록해주었다.

    이 때 지난 번에 소개한 preventDefault라는 Event modifier를 이용하여 form 태그의 기본 동작을 막아주었다.

     

    이제 form 태그 안에 있는 button을 클릭하면 submit 이벤트가 발생하여 handleSubmit 함수가 실행될 것이다.

     

    (bind:value는 아래 글에서 자세히 설명했으므로 설명은 pass~)

     

    https://im-developer.tistory.com/205

     

    [Svelte] Svelte 기초 - Data binding과 Reactive Values

    Input & Data binding Hello {name}! {color} jean! update jean color 이렇게 color 변수를 선언한 후에 아래 {color} jean! 을 출력하면 화면에 black jean!이라는 단어가 출력된다. ({}는 동적인 값을 넣을 때..

    im-developer.tistory.com

     

     

    - Checkbox

    <script>
      let name;
      let age;
      let fighting = false;
      let sneaking = false;
      let running = false;
    </script>
    
    <h3>Add a new person</h3>
    <form on:submit|preventDefault={handleSubmit}>
      <input type="text" placeholder="name" bind:value={name} />
      <input type="number" placeholder="age" bind:value={age} />
      <h4>Skills:</h4>
      <label>
        <input type="checkbox" bind:checked={fighting} />fighting<br />
      </label>
      <label>
        <input type="checkbox" bind:checked={sneaking} />sneaking<br />
      </label>
      <label>
        <input type="checkbox"  bind:checked={running}/>running<br />
      </label>
      <button>Add Person</button>
    </form>
    

     

    input text나 number는 bind:value를 이용해 바인딩했으나

    문제는 checkbox와 같은 태그이다.

     

    한 가지 방법은 각 checkbox 별로 boolean 값을 가지는 변수를 만들고 

    checked 속성을 bind해주는 방법이다.

     

    그러나 이렇게 했을 경우 checkbox 개수만큼 변수의 개수가 늘어나 코드가 지저분해 진다는 단점이 있다.

     

     

     

    <script>
      let name;
      let age;
      let skills = [];
      
      const handleSubmit = () => {
        console.log(skills);
      };
    </script>
    
    <h3>Add a new person</h3>
    <form on:submit|preventDefault={handleSubmit}>
      <input type="text" placeholder="name" bind:value={name} />
      <input type="number" placeholder="age" bind:value={age} />
      <h4>Skills:</h4>
      <label>
        <input type="checkbox" bind:group={skills} value="fighting" />fighting<br />
      </label>
      <label>
        <input type="checkbox" bind:group={skills} value="sneaking" />sneaking<br />
      </label>
      <label>
        <input type="checkbox" bind:group={skills} value="running" />running<br />
      </label>
      <button>Add Person</button>
    </form>
    

     

    이 경우에는 이렇게 배열을 먼저 선언하고,

    각 checkbox에 bind:group을 이용하여 배열을 바인딩하면 된다.

     

     

    이제 Form에서 fighting과 sneaking을 체크한 후에 버튼을 클릭하고 console 창을 확인해보면,

    이렇게 skills 배열에 fighting과 sneaking이 들어와있는 것을 확인할 수 있다.

     

     

     

    - Select

    <script>
      let name;
      let hairColor;
      let age;
      let skills = [];
    
      const handleSubmit = () => {
        console.log(name, hairColor, age, skills);
      };
    </script>
    
    <h3>Add a new person</h3>
    <form on:submit|preventDefault={handleSubmit}>
      <input type="text" placeholder="name" bind:value={name} />
      <input type="number" placeholder="age" bind:value={age} />
      <h4>Skills:</h4>
      <label>
        <input type="checkbox" bind:group={skills} value="fighting" />fighting<br />
      </label>
      <label>
        <input type="checkbox" bind:group={skills} value="sneaking" />sneaking<br />
      </label>
      <label>
        <input type="checkbox" bind:group={skills} value="running" />running<br />
      </label>
      <h4>hairColor:</h4>
      <select bind:value={hairColor}>
        <option value="black">black</option>
        <option value="orange">orange</option>
        <option value="brown">brown</option>
        <option value="silver">silver</option>
      </select>
      <button>Add Person</button>
    </form>
    
    <style></style>
    

     

    select 태그에도 bind:value를 사용하여 바인딩할 수 있다.

    이 경우에 바인딩된 hairColor 변수에는 option 태그의 value 값이 들어간다.

     

     

     

    Custom Event Dispatching

    만약에 AddPersonForm 내부에서 submit 이벤트가 실행됐을 때,

    각 변수에 저장된 input 값들이 AddPersonForm 상위 컴포넌트에 선언된

    데이터에 추가되려면 어떻게 할 수 있을까?

     

    Event forwarding을 떠올릴 수도 있겠지만, Event forwarding의 경우

    하위 컴포넌트에 이벤트 handler가 등록되어 있지 않을 때 부모 컴포넌트의 handler를 그대로 가져와 사용한다는 개념으로,

    하위 컴포넌트에서 특정 데이터를 상위로 넘겨 줄 방법은 없다.

     

    이처럼 하위에서 상위로 데이터 전달을 해야 하는 경우

    Custom Event dispatcher를 이용할 수 있다.

     

    JavaScript의 Custom Event 기능을 이용한 기능인데, svelte에서 쉽게 사용하도록 여러 메소드를 제공한다.

    (Custom Event는 예전에 아래 포스팅에서 한 번 다뤄본 적이 있다.)

     

    https://im-developer.tistory.com/190?category=846746

     

    [JS/CustomEvent] 자바스크립트, 커스텀 이벤트 생성하기

    회사에서 이번에 새로 맡은 업무를 기획중인데, Native 앱이 웹뷰에 뭔가를 요청할때마다 웹뷰에서 이벤트가 trigger되도록 만들어야해서 어떻게 할지 엄청 고민을 많이 했었다. 웹뷰가 Native Client��

    im-developer.tistory.com

     

     

    <script>
      import { createEventDispatcher } from 'svelte';
    
      let dispatch = createEventDispatcher();
    
      let name;
      let hairColor;
      let age;
      let skills = [];
    
      const handleSubmit = () => {
        const person = {
          name,
          hairColor,
          age,
          skills,
          id: Math.random()
        };
    
        dispatch('addPerson', person);
      };
    </script>

     

    일단 event를 생성하려면 svelt에서 제공하는 'createEventDispatcher' 함수를 import한다.

    그리고 이 함수를 실행하여 dispatch라는 함수를 생성한다.

     

    이 함수는 2가지 parameter를 넣을 수 있는데,

    하나는 string으로 custom event의 이름이 된다.

    두 번째 parameter로는 Custom event handler에 넘겨 줄 데이터를 넣을 수 있다.

     

    이제, handlerSubmit이 실행되면, addPerson이라는 이름의 Custom Event가 생성된 후,

    person 이라는 데이터와 함께 이벤트가 dispatch된다.

     

    <script>
      import Modal from './Modal.svelte';
      import AddPersonForm from './AddPersonForm.svelte';
    
      let showModal = false;
    
      const toggleModal = () => {
        showModal = !showModal;
      };
    
      let people = [
        { name: 'juno', hairColor: 'brown', age: 25, id: 1 },
        { name: 'mario', hairColor: 'black', age: 45, id: 2 },
        { name: 'lily', hairColor: 'pink', age: 35, id: 3 },
      ];
    
      const addPerson = ({ detail: person }) => {
        people = [person, ...people];
        showModal = false;
      };
    </script>
    
    <Modal {showModal} on:click={toggleModal}>
      <AddPersonForm on:addPerson={addPerson} />
    </Modal>

     

    그러면 이제 AddPersonForm 컴포넌트를 사용하는 곳에서 

    아까 지정한 Custom Event의 name을 그대로 사용하여 on: 과 함께 어떤 특정 함수를 이벤트 handler로 등록할 수 있다.

     

    이벤트 handler로 등록된 함수는 event 객체를 파라미터로 받는데,

    그 객체의 detail 속성으로 person 데이터가 들어오게 된다.

     

    이제 이 person 데이터를 이용해, 부모 컴포넌트에 선언 된 데이터에 

    새로운 데이터를 추가, 삭제, 수정 등 여러 조작을 할 수 있게 된다.

     

    여기서 꼭 주의해야 하는 점은 svelte에서는 어떤 변수가 재할당될 때
    그 변수와 연관된 모든 dom이 reactive하게 반응한다.
    따라서 배열이나 객체 변수가 있다면 해당 배열이나 객체를 복사한 후,
    재할당해주는 방식으로 업데이트해야만 reactive한 app을 개발할 수 있다.
    반응형

    COMMENT