[Nuxt.js]Modal Props Data

babypig·2022년 10월 18일
1

Nuxt.js

목록 보기
6/10
post-thumbnail

📌 전 포스팅 - Modal props로 수정 혹은 등록 시 data 보내기 보완

  1. 부모 컴포넌트 기본 구조
<div class="list">
      <h3 class="mb-16">도슨트</h3>
      <div class="list-top mb-16">
        <SButton>삭제</SButton>
       <SButton button-type="primary" @click="onRegisterDocentModal(true)">등록</SButton>
      </div>
      <table class="admin-table">
        <thead>
          <tr>
            <th><SCheckbox /></th>
            <th>썸네일</th>
            <th>작품명</th>
            <th>소개글</th>
            <th>지도</th>
            <th>오디오</th>
            <th>수정</th>
          </tr
        </thead>
        <tbody v-if="!detailData.infos || !detailData.infos[0]">
          <tr>
            <td colspan="11"><div>리스트가 없습니다.</div></td>
          </tr>
        </tbody>
        <Draggable v-bind="dragOptions" v-model="detailData.infos" tag="tbody">
          <tr v-for="(item, index) in detailData.infos" :key="item.id">
            <td>
              <div>
                <SCheckbox />
              </div>
            </td>
            <td>
              <div class="img">
                <img :src="`${$store.state.BASE_URL}${item.thumbnail?.savedFileName}`" alt="테스트" />
              </div>
            </td>
            <td>
              <div class="text-left">
                {{ item.title }}
              </div>
            </td>
            <td>
              <div class="text-left">
                {{ item.intro }}
              </div>
            </td>
            <td>
              <div>
                {{ item.map ? 'Y' : 'N' }}
              </div>
            </td>
            <td>
              <div>
                {{ item.audio ? 'Y' : 'N' }}
              </div>
            </td>
            <td>
              <div>
                <SButton w-size="small" @click="onRegisterDocentModal(false, index)">수정</SButton>
              </div>
            </td>
          </tr>
        </Draggable>
      </table>
    </div>
		<DocentRegistModal
      :is-show="modal.isRegistDocent"
      :docent-data="selectedDocent"
      @close="modal.isRegistDocent = false"
      @save="ModifiedDocentModal"
    />
  1. 모달 컴포넌트 기본 구조
<template>
  <transition name="fade">
    <div v-if="isShow" class="modal-wrap">
      <div class="modal-inner">
        <div class="modal">
          <div class="head">
            <button type="button" class="close-btn" @click="cancel">
              <i class="ic-close" />
            </button>
          </div>
          <div class="body">
            <div class="contents-info mb-24">
              <div class="representative-img mr-16">
                <label class="upload-img" @click.stop>
                  <img
                    v-if="thumbnail?.savedFileName"
                    :src="`${$store.state.BASE_URL}${thumbnail?.savedFileName}`"
                    :alt="`${thumbnail?.originalFileName}`"
                  />
                  <span v-if="!thumbnail?.savedFileName" class="file-info">
                    <i class="ic-plus mb-16"></i>
                    <span class="bt-2r">이미지를 등록해주세요.</span>
                    <span class="nt-5">5MB 이하의 JPG, GIF, PNG파일을 선택해주세요.</span>
                    <input
                      type="file"
                      accept=".jpg, .png, .gif"
                      class="is-blind"
                      @change="fileUpload($event, 'thumbnail')"
                    />
                  </span>
                </label>
                <SButton
                  v-if="thumbnail?.savedFileName"
                  button-type="primary"
                  w-size="small"
                  h-size="small"
                  @click.self="onDeleteFile('thumbnail')"
                >
                  삭제
                </SButton>
              </div>
              <div class="works-info">
                <SInput v-model="title" w-size="full" class="mb-14" placeholder="제목" />
                <SInput v-model="writer" w-size="full" class="mb-14" placeholder="작가명" />
                <SInput v-model="position" w-size="full" placeholder="작품위치" />
              </div>
            </div>
            <div class="mb-24">
              <STextarea v-model="intro" placeholder="작품 소개" />
            </div>
            <div class="mb-12">
              <div class="file-list">
                <label class="mt-2m">음성파일</label>
                <SInput :value="getFileName('audio')" class="file-input mr-8" readonly />
                <SButton v-if="!audio" @click="onFileClick('audioUpload')">파일 첨부</SButton>
                <template v-else>
                  <a
                    :href="`/api/file/download?path=${audio.savedFileName}&fileName=${audio.originalFileName}`"
                    download
                    class="download primary mr-8"
                    >다운로드</a
                  >
                  <SButton w-size="small" @click="onDeleteFile('audio')">삭제</SButton>
                </template>
                <input
                  ref="audioUpload"
                  type="file"
                  accept=".mp3, .wave"
                  class="is-blind"
                  @change="fileUpload($event, 'audio')"
                />
              </div>
              <p class="bt-2r">15MB 이하의 MP3, WAVE 파일</p>
            </div>
            <div>
              <div class="file-list">
                <label class="mt-2m">지도 이미지</label>
                <SInput :value="getFileName('map')" class="file-input mr-8" readonly />
                <SButton v-if="!map" @click="onFileClick('mapUpload')">파일 첨부</SButton>
                <template v-else>
                  <a
                    :href="`/api/file/download?path=${map.savedFileName}&fileName=${map.originalFileName}`"
                    download
                    class="download primary mr-8"
                    >다운로드</a
                  >
                  <SButton w-size="small" @click="onDeleteFile('map')">삭제</SButton>
                </template>
                <input
                  ref="mapUpload"
                  type="file"
                  accept=".png, .jpg, .jpeg, .gif"
                  class="is-blind"
                  @change="fileUpload($event, 'map')"
                />
              </div>
              <p class="bt-2r">{가로}px {세로}px 5MB 이하의 PNG, JPG, JPEG, GIF 파일</p>
            </div>
          </div>
          <div class="foot-wrap">
            <div class="foot">
              <SButton class="mr-8" @click="cancel">취소</SButton>
              <SButton button-type="primary" @click="saveDocent">완료</SButton>
            </div>
          </div>
        </div>
      </div>
      <SDialogModal no-scroll-lock :is-show="isShowErrorModal" @close="isShowErrorModal = false">
        <template #content>{{ errorModalMsg }}</template>
        <template #modal-btn2>
          <SButton button-type="primary" @click="isShowErrorModal = false">확인</SButton>
        </template>
      </SDialogModal>
    </div>
  </transition>
</template>
  1. 부모컴포넌트 스크립트 작성

default로 넣어줄 data 를 만들어준다.
isNew의 boolean 값에 따라 기존 data를 가져오거나 defaultData를 넣어줘 등록과 수정을 구분하고 targetDocentselectedDocent에 담아 props로 전달

<script>
	export default {
	async asyncData({ params, $axios, redirect, $dayjs }) {
    const { id } = params;
    const isNew = id == null;
    const detailData = id
      ? await $axios
          .$get(`/admin/docents/${id}`)
          .then((detailData) => ({
            ...detailData,
            startDate: $dayjs(detailData.startDate).format('YYYY-MM-DD'),
            endDate: $dayjs(detailData.endDate).format('YYYY-MM-DD')
          }))
          .catch(() => {
            redirect('/admin/common/docent');
          })
      : cloneDeep(DOCENTS_DETAIL);
    return { id, isNew, detailData };
  },
		data() {
			return {
				isNew: false,
				detailData: null,
				selectedDocent: null,
			}
		},
		methods: {
			onRegisterDocentModal(isNew, index) {
      const defaultDocent = {
        thumbnail: null,
        title: '',
        writer: '',
        position: '',
        intro: '',
        audio: null,
        map: null
      };

      const targetDocent = !isNew ? this.detailData.infos[index] : defaultDocent;

      this.selectedDocent = {
        ...targetDocent,
        isNew,
        index
      };
      this.modal.isRegistDocent = true;
    },
		}
	}
</script>
  1. 모달 컴포넌트 스크립트 작성

props로 받은 default 값 정의 후 watch로 isShow를 감지하여 data 넣어줌,
resetData() 함수로 취소 시에 모달에 작성해놓은 data들을 다시 원 상태로 되돌려준다.

<script>

export default {
  props: {
    docentData: {
      type: Object,
      required: false,
      default: () => ({
        isNew: true,
        index: null,
        thumbnail: null,
        title: '',
        writer: '',
        position: '',
        intro: '',
        audio: null,
        map: null
      })
    },
    data() {
      return {
        isNew: true,
        thumbnail: null,
        title: '',
        writer: '',
        position: '',
        intro: '',
        audio: null,
        map: null,
        isShowErrorModal: false,
        errorModalMsg: ''
      };
    },
    watch: {
      isShow(newValue) {
        console.log(newValue);
        if (newValue) {
          this.isNew = this.docentData.isNew;
          this.thumbnail = this.docentData.thumbnail;
          this.title = this.docentData.title;
          this.writer = this.docentData.writer;
          this.position = this.docentData.position;
          this.intro = this.docentData.intro;
          this.audio = this.docentData.audio;
          this.map = this.docentData.map;
        }
      }
    },
    methods: {
      resetData() {
        this.thumbnail = null;
        this.title = '';
        this.writer = '';
        this.position = '';
        this.intro = '';
        this.audio = null;
        this.map = null;
      },
      cancel() {
        this.resetData();
        this.$emit('close');
      },
    }
  }
}
</script>
  1. 저장할 시에 모달 컴포넌트 스크립트

벨리데이션 체크 후 통과 시 data 를 담아서 $emit으로 전달


saveDocent() {
      if (this.isValidate()) {
        const newDocent = {
          thumbnail: this.thumbnail,
          title: this.title,
          writer: this.writer,
          position: this.position,
          intro: this.intro,
          audio: this.audio,
          map: this.map
        };

        this.$emit('save', { newDocent, isNew: this.isNew, index: this.docentData.index });
        this.resetData();
      }
    },
  1. 저장할 시에 부모 컴포넌트 스크립트

newDocent를 받아 등록일 시 infos에 push 시켜주고 수정일땐 덮어씌워줌

modifiedDocentModal({ newDocent, isNew, index }) {
      if (isNew) {
        this.detailData.infos.push(newDocent);
      } else {
        this.detailData.infos[index] = {
          ...this.detailData.infos[index],
          ...newDocent
        };
      }
      this.modal.isRegistDocent = false;
    },
profile
babypig

0개의 댓글