HTML 양식을 JSON으로 쉽게 변환하는 방법

내용물


  • Intro
  • Form Data
  • Gotcha's
  • Examples
  • Summary

  • 소개

    I have a love, but sometimes hate, relationship with HTML Forms. HTML Forms are absolutely brilliant for out of the box validation, accessibility and usability. But they can be a pain to style!
    Nevertheless, HTML Forms give you massive amounts of functionality with zero dependencies.

    If you are anything like me, you prefer your API to be JSON based. Making it easier and more consistent to deal with requests and responses on the backend.
    You could add a middleware to your API endpoint that's going to handle your Form UI but why make that endpoint different from the rest?

    What if you could send your Form data off in JSON format and handle it like all your other endpoints. Now you can!

    TLDR; Skip to the examples

    양식 데이터

    Introducing FormData , 이것은 HTML 양식에서 데이터를 조작하기 위한 정말 좋은 웹 API입니다.

    이를 통해 다음을 사용하여 HTML 양식을 JSON으로 쉽게 변환할 수 있습니다.
  • DOM에서 양식 요소를 가져옵니다.

  • const formElement = document.querySelector('form')
    

  • 다음 함수에 양식을 전달

  • /**
     * Creates a json object including fields in the form
     *
     * @param {HTMLElement} form The form element to convert
     * @return {Object} The form data
     */
    const getFormJSON = (form) => {
      const data = new FormData(form);
      return Array.from(data.keys()).reduce((result, key) => {
        result[key] = data.get(key);
        return result;
      }, {});
    };
    

  • JSON 개체 결과를 처리하지만 양식의 데이터를 처리하고 싶습니다! 예를 들어 Fetch으로 보내십시오.

  • 갓챠스

    As with everything these are a few gotchas to look out for!

    체크박스



    체크박스를 선택하면 결과에 '켜기'로 표시됩니다. 아마도 원하는 부울이 아닐 것입니다.
    예를 들어, 사용자가 확인한 양식에 이 입력이 있는 경우.

    <input name="isOpen" type="checkbox" checked />
    


    위의 함수를 사용하여 생성합니다.

    {
      "isOpen": "on"
    }
    


    당신은 아마도 속성을 확인하고 그것이 'on'인지 확인하고 그것을 부울로 변환하기를 원할 것입니다.

    파일 업로드



    다음과 같이 여러 파일을 허용하는 파일 입력이 있는 경우 이것은 정말 저를 사로 잡았습니다.

    <input name="uploads" type="file" multiple />
    


    하나의 파일이 업로드되면 File 개체를 얻게 됩니다.
    그러나 여러 파일을 업로드한 경우 실제로 파일 목록이 표시됩니다.

    다행히도 파일 목록을 일관되게 제공하기 위한 정말 간단한 수정 사항이 있습니다.
    결과에서 파일을 가져와 다음과 같이 처리합니다.

    [files].flat().filter((file) => !!file.name)
    


    이렇게 하면 단일 파일만 업로드되거나 파일이 업로드되지 않거나 여러 파일이 업로드되는 경우 처리하여 일관되게 파일 목록을 제공합니다.

    이것은 또한 예를 들어 파일 크기 및 제한에 대해 더 많은 클라이언트 측 검사를 수행할 수 있음을 의미합니다.

    이름이 같은 입력



    가능한 태그 목록이 있고 사용자가 다음과 같이 어떤 프로그래밍 언어를 알고 있는지 적용할 수 있는 태그를 선택할 수 있다고 가정해 보겠습니다.

    <input name="tags" type="checkbox" value="javascript" />
    <input name="tags" type="checkbox" value="python" />
    


    현재 솔루션을 사용하면 키가 축소에서 재정의되므로 마지막으로 선택한 확인란만 가져옵니다. 그러나 이에 대한 간단한 수정도 있습니다.

    결과에 키(입력의 이름 속성)가 이미 존재하는지 확인하고, 존재하는 경우 결과 목록을 가져오는 getAll 메서드를 사용합니다.

    /**
     * Creates a json object including fields in the form
     *
     * @param {HTMLElement} form The form element to convert
     * @return {Object} The form data
     */
    const getFormJSON = (form) => {
      const data = new FormData(form);
      return Array.from(data.keys()).reduce((result, key) => {
        if (result[key]) {
          result[key] = data.getAll(key)
          return result
        }
        result[key] = data.get(key);
        return result;
      }, {});
    };
    


    마찬가지로 이전에 파일을 업로드할 때 이와 같이 하나의 틱만 처리하고 틱 또는 다중 처리는 하지 않아야 합니다.

    [result.tags || []].flat();
    


    Shut up and show me the code.

  • Interactive
  • Simple
  • Full
  • Bonus: Example Test


  • 간단한 예

    <!doctype html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8">
    </head>
    
    <body>
      <form name="forms" id="forms">
        <label>Whats your username?
          <input name="username" type="text" />
        </label>
        <label>How many years have you been a developer?
          <input name="age" type="number" />
        </label>
        <button type="submit">Submit</button>
      </form>
    
      <script>
        // get the form element from dom
        const formElement = document.querySelector('form#forms')
    
        // convert the form to JSON
        const getFormJSON = (form) => {
          const data = new FormData(form);
          return Array.from(data.keys()).reduce((result, key) => {
            result[key] = data.get(key);
            return result;
          }, {});
        };
    
        // handle the form submission event, prevent default form behaviour, check validity, convert form to JSON
        const handler = (event) => {
          event.preventDefault();
          const valid = formElement.reportValidity();
          if (valid) {
            const result = getFormJSON(formElement);
            console.log(result)
          }
        }
    
        formElement.addEventListener("submit", handler)
      </script>
    </body>
    

    전체 예

    <!doctype html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8">
    </head>
    
    <body>
      <form name="forms" id="forms">
        <label>Whats your username?
          <input name="username" type="text" />
        </label>
        <label>How many years have you been a developer?
          <input name="age" type="number" />
        </label>
    
        <label>Upload images
          <input name="images" type="file" accept="image/png, image/jpeg" multiple />
        </label>
    
        <label>Do you know javascript?
          <input name="languages" type="checkbox" value="javascript" />
        </label>
        <label>Do you know python?
          <input name="languages" type="checkbox" value="python" />
        </label>
    
        <label>Enjoyed this blog?
          <input name="isHappyReader" type="checkbox" />
        </label>
    
        <button type="submit">Submit</button>
      </form>
    
      <script>
        // get the form element from dom
        const formElement = document.querySelector('form#forms')
    
        // convert the form to JSON
        const getFormJSON = (form) => {
          const data = new FormData(form);
          return Array.from(data.keys()).reduce((result, key) => {
            if (result[key]) {
              result[key] = data.getAll(key)
              return result
            }
            result[key] = data.get(key);
            return result;
          }, {});
        };
    
        // handle the form submission event, prevent default form behaviour, check validity, convert form to JSON
        const handler = (event) => {
          event.preventDefault();
          const valid = formElement.reportValidity();
          if (valid) {
            const result = getFormJSON(formElement);
            // handle one, multiple or no files uploaded
            const images = [result.images].flat().filter((file) => !!file.name)
            // handle one, multiple or no languages selected
            const languages = [result.languages || []].flat();
            // convert the checkbox to a boolean
            const isHappyReader = !!(result.isHappyReader && result.isHappyReader === 'on')
    
            // use spread function, but override the keys we've made changes to
            const output = {
              ...result,
              images,
              languages,
              isHappyReader
            }
            console.log(output)
          }
        }
    
        formElement.addEventListener("submit", handler)
      </script>
    </body>
    

    보너스: 예제 테스트

    it('should return a JSON representation of a form', () => {
      const form = document.createElement('form');
    
      const input = document.createElement('input');
      input.name = 'test';
      input.value = 'value';
      form.appendChild(input);
    
      const number = document.createElement('input');
      number.type = 'number';
      number.name = 'int';
      number.value = '10';
      form.appendChild(number);
    
      const result = getFormJSON(form);
      expect(result).to.deep.equal({
        test: 'value',
        int: '10',
      });
    });
    

    요약

    In summary, you can use what browsers give you to get all the great benefits of HTML Forms, and then convert it to JSON so it's easier to work with the data! I hope this has been useful.

    Happy Form building!

    Would you be interested in a series of what you can achieve with HTML and Web APIs?
    What are you favourite web tips and tricks?

    좋은 웹페이지 즐겨찾기