programing

vuejs/변수 값을 사용하여 양방향 바인딩 제한 다른 변수 수정 시 변경

goodsources 2022. 8. 30. 22:34
반응형

vuejs/변수 값을 사용하여 양방향 바인딩 제한 다른 변수 수정 시 변경

mapGetter를 통해 내 스토어에서 얻은 클라이언트 목록을 포함하는 'client-display' 컴포넌트가 있습니다.목록 위에 'v-for'를 사용하여 모든 항목을 'v-for-panel'로 표시하므로 클라이언트 = 패널 하나가 됩니다.이들 패널의 헤더에는 클라이언트의 소품으로 전달된 '편집-삭제' 컴포넌트가 있습니다.이 "edit-delete"는 기본적으로 payload에 대한 해당 아이콘을 클릭하면 "edit" 또는 "delete" 이벤트만 발생합니다.편집 아이콘을 클릭하면 편집 이벤트가 '클라이언트 디스플레이'에 캐치되므로 클라이언트를 '클라이언트'라는 변수에 할당할 수 있습니다(좀 헷갈리긴 하지만).이 변수를 내 대화 상자에 소품으로 전달하고 이 대화 상자를 사용하여 클라이언트를 편집합니다.

문제는 클라이언트를 편집할 때 올바르게 편집되지만 [취소]를 클릭하면 UI에서 발생한 내용을 되돌릴 수 없다는 것입니다.오래된 값을 가진 오브젝트를 유지하고 취소 이벤트에서 리셋하려고 했지만, 어떤 일이 있어도 오브젝트에 보관하려고 하는 기준값마저 바뀌어 가장 놀라운 일이었습니다.이를 위해 새로운 개체를 시작하고 값을 수동으로 할당하거나 Object.assign()을 사용하는 등 여러 가지 작업을 시도했습니다.이 모든 것을 풀려고 여러 가지 방법을 시도해봤지만 잘 되지 않았다.변경 내용이 UI에 표시되기 전에 스토어에서 커밋될 때까지 기다리거나 참조 개체를 사용하여 '취소' 이벤트의 값을 재설정할 수 있습니다.

코드와 관련된 부분은 다음과 같습니다(읽기 쉽게 하기 위해 많은 것을 제거했지만 필요한 것은 모두 갖추어져 있습니다).

내 스토어의 클라이언트 모듈

이 부분은 고객을 제대로 확보했기 때문에 잘 작동한다고 생각합니다만, 뭔가 바인딩되어 있어서는 안 됩니다.

const state = {
  clients: null,
};

const getters = {
  [types.CLIENTS] : state => {
    return state.clients;
  },
};

const mutations = {
  [types.MUTATE_LOAD]: (state, clients) => {
    state.clients = clients;
  },
};

const actions = {
  [types.FETCH]: ({commit}) => {
    clientsCollection.get()
      .then((querySnapshot) => {
        let clients = querySnapshot.docs.map(doc => doc.data());
        commit(types.MUTATE_LOAD, clients)
    }).catch((e) => {
      //...
    });
  },
}

export default {
  state,
  getters,
  mutations,
  ...
}

ClientsDisplay 컴포넌트

<template>
  <div>
    <div>
      <v-expansion-panels>
        <v-expansion-panel
          v-for="c in clientsDisplayed"
          :key="c.name"
        >
          <v-expansion-panel-header>
            <div>
              <h2>{{ c.name }}</h2>
              <edit-delete
                :element="c"
                @edit="handleEdit"
                @delete="handleDelete"
              />
            </div>
          </v-expansion-panel-header>
          <v-expansion-panel-content>
            //the client holder displays the client's info
            <client-holder
              :client="c"
            />
          </v-expansion-panel-content>
        </v-expansion-panel>
      </v-expansion-panels>
    </div>
    <client-add-dialog
      v-model="clientPopup"
      :client="client"
      @cancelEdit="handleCancel"
    />
  </div>
</template>

<script>
  import { mapGetters, mapActions } from 'vuex';
  import * as clientsTypes from '../../../../store/modules/clients/types';
  import ClientDialog from './ClientDialog';
  import EditDelete from '../../EditDelete';
  import ClientHolder from './ClientHolder';
  import icons from '../../../../constants/icons';

  export default {
    name: 'ClientsDisplay',
    components: {
      ClientHolder,
      ClientAddDialog,
      EditDelete,
    },
    data() {
      return {
        icons,
        clientPopup: false,
        selectedClient: null,
        client: null,
        vueInstance: this,
      }
    },
    created() {
      this.fetchClients();
    },
    methods: {
      ...mapGetters({
        'stateClients': clientsTypes.CLIENTS,
      }),
      ...mapActions({
        //this loads my clients in my state for the first time if needed
        'fetchClients': clientsTypes.FETCH,
      }),
      handleEdit(client) {
        this.client = client;
        this.clientPopup = true;
      },
      handleCancel(payload) {
        //payload.uneditedClient, as defined in the dialog, has been applied the changes
      },
    },
    computed: {
      isMobile,
      clientsDisplayed() {
        return this.stateClients();
      },
    }
  }
</script>

EditDelete 컴포넌트

<template>
  <div>
    <v-icon
      @click.stop="$emit('edit', element)"
    >edit</v-icon>
    <v-icon
      @click.stop="$emit('delete', element)"
    >delete</v-icon>
  </div>
</template>

<script>
  export default {
    name: 'EditDelete',
    props: ['element']
  }
</script>

ClientDialog 컴포넌트

주의사항: headerTitle은 클라이언트 이름이 변경되어도 그대로 유지됩니다.

<template>
  <v-dialog
    v-model="value"
  >
    <v-card>
      <v-card-title
        primary-title
      >
        {{ headerTitle }}
      </v-card-title>
      <v-form
        ref="form"
      >
        <v-text-field
          label="Client name"
          v-model="clientName"
        />
        <address-fields
          v-model="clientAddress"
        />
      </v-form>
      <v-card-actions>
        <v-btn
          @click="handleCancel"
          text
        >Annuler</v-btn>
        <v-btn
          text
          @click="submit"
        >Save</v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

<script>
  import AddressFields from '../../AddressFields';

  export default {
    name: 'ClientDialog',
    props: ['value', 'client'],
    components: {
      AddressFields,
    },
    data() {
      return {
        colors,
        clientName: '',
        clientAddress: { province: 'QC', country: 'Canada' },
        clientNote: '',
        uneditedClient: {},
      }
    },
    methods: {
      closeDialog() {
        this.$emit('input', false);
      },
      handleCancel() {
        this.$emit('cancelEdit', { uneditedClient: this.uneditedClient, editedClient: this.client})
        this.closeDialog();
      },
    },
    computed: {
      headerTitle() {
        return this.client.name
      }
    },
    watch: {
      value: function(val) {
        // I watch there so I can reset the client whenever I open de dialog
        if(val) {
          // Here I try to keep an object with the value of this.client before I edit it
          // but it doesn't seem to work as I intend
          Object.assign(this.uneditedClient, this.client);
          this.clientName = this.client.name;
          this.clientContacts = this.client.contacts;
          this.clientAddress = this.client.address;
          this.clientNote = '';
        }
      }
    }
  }
</script>

데이터의 개별 복사본을 유지하려면 klona와 같은 항목을 사용하여 개체의 심층 복사본을 수행해야 합니다.Object.assign을 사용하는 것은 얕은 복사이며 참조 값의 변경으로부터 보호되지 않습니다.

언급URL : https://stackoverflow.com/questions/63385761/limiting-the-two-way-binding-with-vuejs-variable-values-change-when-modifying

반응형