[이슈] input 태그에 파일을 여러 번 파일을 등록할 시 발생되는 이슈

2023. 12. 29. 14:58이슈 창고

728x90
SMALL

[Reason]

view 단을 만들고 이미지를 수정하는 부분을 만들어 업로드한 이미지들이 back 단으로 넘어가면 수정되는 코드를 작성하였다.

업로드하는 input 태그의 속성은 multiple 로서, 다중 이미지 파일이 업로드 될 수 있다.

코드 작성완료 후 기능 수행을 진행했을 때 여러 개의 이미지를 넣었을 때 정상적으로 반영되는 것을 확인할 수 있었다.

 

그런데, 유저 테스트를 진행하는 도중에 이미지가 정상적으로 반영이 되지 않는다는 문의를 받게 되었다.

한 번 버튼을 눌러 새로운 이미지를 추가하고 다시 반복적으로 한 번 더 버튼을 눌러 새로운 이미지를 눌러 추가하였더니 2개의 이미지가 반영되지 않고 1개의 이미지만이 반영되어 들어갔다는 이슈였다.

 

즉, 최신 업로드 이미지로 덮어씌워져 반영되는 이슈이다.

 

 

[Solution]

확인해보니, 파일 타입의 input 태그는 기본적으로 한 번 업로드를 수행하면 그 뒤에 다시 업로드 수행 시 최신 업로드 파일로 덮어씌워지는 특성을 가지고 있었다.

 

이를 제어하고 기존의 업로드 이미지 파일들은 유지하면서 반영되기 위해서는 DataTransfer 라고 하는 기능을 사용하여 파일들을 제어해야 한다.

 

 

- 이미지 업로드 HTML 코드

<ul id="imageList" class="imageList">
</ul>
<input id='addPic' type="file" accept="image/*" multiple style='display: none;'
       name="updateProjectImages" onchange="inputNewImg(this);">
<label for='addPic'>
    <button type='button'
            onclick="document.getElementById('addPic').click(); ">사진 추가하기
    </button>
</label>

 

 

 - 이미지를 유지시키고 업로드한 이미지들을 노출시키는 JS 코드

// 업로드 파일들을 유지시키면서 가지고 최종적으로 보낼 파일 리스트를 반영시키기 위한 객체
const updateDataTransfer = new DataTransfer();

// 새로 추가할 이미지들에 대한 업로드
function inputNewImg(input) {
    // 업로드할 파일들
    const files = input.files;

    // id가 addPic인 파일 타입의 input 태그에 업로드 되어있는 상태인 파일들 리스트
    let prevImages = document.getElementById('addPic').files;

    // 만약 기존에 업로드 되어있는 파일들이 존재할 경우
    if(prevImages != null && prevImages.length > 0){
        // 현재 업로드할 파일들을 updateDataTransfer에 추가
        for(var j = 0; j < files.length ; j++){
            updateDataTransfer.items.add(files[j]);
        }
        
        // id가 addPic인 파일 타입의 input 태그에 업로드 되어있는 상태인 파일들 리스트를
        // 현재 추가하여 넣은 updateDataTransfer의 파일들로 교체(최신화)
        document.getElementById("addPic").files = updateDataTransfer.files;
        
    // 만약 기존 업로드 파일이 존재하지 않는 초기 상태일 경우
    }else{
        // 현재 업로드할 파일들을 updateDataTransfer에 추가
        for(var k = 0; k < files.length ; k++){
            updateDataTransfer.items.add(files[k]);
        }
        
        // id가 addPic인 파일 타입의 input 태그에 업로드 되어있는 상태인 파일들 리스트를
        // 현재 추가하여 넣은 updateDataTransfer의 파일들로 교체(최신화)
        document.getElementById("addPic").files = updateDataTransfer.files;
    }

    // 추가한 이미지들을 view 단에서 노출시키기 위한 html 변수
    var html = '';
    
    // 업로드할 파일들을 조회하면서 형식에 맞게 노출되게끔 html 코드를 구성하여 html 변수에 적재
    for (let i = 0; i < files.length; i++) {
        let src = URL.createObjectURL(files[i]);

        html += `
                        <li style="position: relative" id="newPic${i}" class="useImages">
                             <img src="${src}" style="max-width: 100px; width: 100px; height: 100px; margin-right: 10px; margin-bottom: 10px;">
                             <button type="button" onclick="deleteNewImg(${i})" style="position: absolute; right: 13px; top:1px; margin: 0; font-size: 15px; background-color: transparent; color: red; padding: 0; border: none; font-weight: bold;" >
                                <span>
                                   X
                                </span>
                             </button>
                          </li>`
    }

    // 최종적으로 노출시킬 태그에 append 시킴
    $('.imageList').append(html);
}

위의 코드와 같이 DataTransfer를 활용하여 업로드 파일들을 유지시키면서 반복 업로드할 경우에도 정상적으로 넣어질 수 있도록 제어해야 한다.

 

여기서 주의해야할 점은, DataTransfer를 위의 inputNewImg 함수에 넣으면 안된다.

왜냐하면, 이미지를 추가할 때마다 inputNewImg 함수가 실행되도록 되어있는데 만약 함수 안에 DataTransfer를 넣게 된다면 기존에 유지시키려고 DataTransfer에 넣어져 있던 이미지들이 초기화되어 유지되지 않는다.

728x90
반응형
LIST