Why the watcher can not detect the change?

39 views Asked by At

In the code below there are App.vue, appSidebar.vue and invoiceContent.vue files, the watcher does not detect the change of clearForm prop in the invoiceContent.vue and console.log("clearForm :>> ", clearForm) is not being executed. Can someone please tell why? I am losing my mind here. I checked when I click the red button in the appSidebar.vue the clearInvoice is being executed and clearForm is being changed to true .

App.vue;

<template>
  <div class="w-screen h-full bg-gray-800 flex flex-row text-white items-start justify-center">
    <app-sidebar
      :invoices="invoiceList"
      :editInvoice="editInvoice"
      :deleteInvoice="deleteInvoice"
      :toggleButton="toggleButton"
      :clearInvoice="clearInvoice"
    />
    <invoice-content
      :saveInvoice="saveInvoice"
      :activeInvoice="state.activeInvoice"
      :showButton="showButton"
      :clearForm="clearForm"
    />
  </div>
</template>
<script setup>
import { reactive, ref } from "vue"
import appSidebar from "./components/appSidebar.vue"
import invoiceContent from "./components/invoiceContent.vue"

const invoiceList = ref([
  {
    id: new Date().getTime(),
    contact: {
      contact_name: "Demo1",
      email: "demo@demo",
      city: "demoland",
      country: "Demoika",
      zipcode: "22222"
    },
    items: [
      {
        id: new Date().getTime(),
        name: "Demo ürün",
        qty: 1,
        unit_price: 10.0,
        total_price: 15.0
      }
    ]
  }
])
const state = reactive({ activeInvoice: null })
const saveInvoice = (invoice) => {
  console.log("invoice :>> ", invoice)
  invoiceList.value.push(invoice)
}
const editInvoice = (invoice) => {
  console.log(invoice)
  state.activeInvoice = invoice
  console.log("state.activeInvoice :>> ", state.activeInvoice)
}

const deleteInvoice = (invoice) => {
  console.log("invoice to be deleted :>>", invoice)
  invoiceList.value = invoiceList.value.filter((i) => i.id !== invoice.id)
}

const showButton = ref(false)

const toggleButton = () => {
  showButton.value = !showButton.value
}

const clearForm = ref(false)

const clearInvoice = () => {
  clearForm.value = !clearForm.value
}
</script>

appSidebar.vue;

<template>
  <aside style="height: 830px" class="bg-gray-700 w-[300px] h-screen">
    <h3 class="text-2xl font-bold mt-2 p-2">Fatura Listesi</h3>
    <div
      v-for="(invoice, i) in invoices"
      :key="invoice.id"
      class="odd:bg-gray-600 flex justify-between items-center p-2"
    >
      <span> #{{ i + 1 }}</span>
      <span>{{ invoice.contact.contact_name }}</span>
      <span>
        <button @click="redButtonClick(invoice)" class="danger-button mr-1">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            class="fill-current"
            height="16"
            viewBox="0 0 24 24"
            width="16"
          >
            <path d="M0 0h24v24H0V0z" fill="none" />
            <path
              d="M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z"
            />
          </svg>
        </button>
        <button @click="purpleButtonClick(invoice)" class="purple-button">
          <svg
            class="fill-current"
            xmlns="http://www.w3.org/2000/svg"
            height="16"
            viewBox="0 0 24 24"
            width="16"
          >
            <path d="M0 0h24v24H0V0z" fill="none" />
            <path
              d="M12 6c3.79 0 7.17 2.13 8.82 5.5C19.17 14.87 15.79 17 12 17s-7.17-2.13-8.82-5.5C4.83 8.13 8.21 6 12 6m0-2C7 4 2.73 7.11 1 11.5 2.73 15.89 7 19 12 19s9.27-3.11 11-7.5C21.27 7.11 17 4 12 4zm0 5c1.38 0 2.5 1.12 2.5 2.5S13.38 14 12 14s-2.5-1.12-2.5-2.5S10.62 9 12 9m0-2c-2.48 0-4.5 2.02-4.5 4.5S9.52 16 12 16s4.5-2.02 4.5-4.5S14.48 7 12 7z"
            />
          </svg>
        </button>
      </span>
    </div>
  </aside>
</template>
<script setup>
const props = defineProps({
  invoices: Array,
  editInvoice: Function,
  deleteInvoice: Function,
  toggleButton: Function,
  clearInvoice: Function
})

const purpleButtonClick = (invoice) => {
  props.editInvoice(invoice)
  props.toggleButton()
}

const redButtonClick = (invoice) => {
  props.deleteInvoice(invoice)
  props.clearInvoice()
}
</script>

invoiceContent.vue;

<template>
  <section class="bg-gray-900 w-3/5 mx-auto mt-10 p-2 px-5 rounded-md shadow-2xl">
    <contact-section :contact="state.contact" />
    <div class="mt-5">
      <app-heading title="Some Title" />
      <invoice-items :items="state.items" :AddInvoiceItem="AddInvoiceItem" />
    </div>
    <invoice-summary :items="state.items" />

    <hr class="bg-gradient-to-r h-[1px] border-none from-gray-700 mt-5" />
    <div id="actionbar" class="actionbar text-right my-5">
      <button v-if="showButton" class="mr-3 purple-button">Update</button>
      <button @click="onSubmit" class="purple-button">Save</button>
    </div>
  </section>
</template>
<script setup>
import { ref, reactive, provide, watch } from "vue"
import invoiceItems from "./invoiceItems.vue"
import invoiceSummary from "./invoiceSummary.vue"
import contactSection from "./contactSection.vue"

const props = defineProps({
  saveInvoice: Function,
  activeInvoice: [Object, null],
  showButton: Boolean,
  clearForm: Boolean
})

const state = reactive({
  id: null,
  created_at: null,
  contact: {
    contact_name: null,
    email: null,
    city: null,
    country: null,
    zipcode: null
  },
  items: []
})
const AddInvoiceItem = () => {
  state.items.push({
    id: new Date().getTime(),
    name: null,
    qty: null,
    unit_price: 0.0,
    total_price: 0.0
  })
}

const DeleteInvoiceItem = (invoiceItem) => {
  state.items = state.items.filter((i) => i.id !== invoiceItem.id)
}

provide("DeleteInvoiceItem", DeleteInvoiceItem)

const onSubmit = () => {
  props.saveInvoice({ ...state, created_at: new Date(), id: new Date().getTime() })
  state.contact = {
    contact_name: null,
    email: null,
    city: null,
    country: null,
    zipcode: null
  }
  state.items = []
}
console.log("props.activeInvoice :>> ", props.activeInvoice)

const actionBarContent = ref('<button class="mr-3 purple-button">Güncelle</button>')

watch(
  () => props.activeInvoice,
  (activeInvoice) => {
    if (activeInvoice) {
      state.contact = { ...activeInvoice.contact }
      state.items = [...activeInvoice.items]
    }
    console.log("activeInvoice :>> ", activeInvoice)
  },
  () => props.showButton,
  (showButton) => {
    if (showButton) {
      actionBarContent.value =
        '<button @click="customAction" class="purple-button">Update</button>'
    } else {
      actionBarContent.value = ""
    }
  },
  () => props.clearForm,
  (clearForm) => {
    if (clearForm) {
      console.log("clearForm :>> ", clearForm)
    }
  }
)
</script>

I tried {immediate: true} in the watcher and I tried to put the clearForm in a watchEffect but still didn't work. I don't know why, I mean showButton is almost the same and that works just fine but this doesn't.

1

There are 1 answers

1
NiyaziGuven On

As @yoduh suggested above I set different watchers for each prop and it works.

  watch(
 () => props.activeInvoice,
  (activeInvoice) => {
    if (activeInvoice) {
      state.contact = { ...activeInvoice.contact }
      state.items = [...activeInvoice.items]
    }
    console.log("activeInvoice :>> ", activeInvoice)
  })
  watch(
 () => props.showButton,
  (showButton) => {
    if (showButton) {
      actionBarContent.value =
        '<button @click="customAction" class="purple-button">Update</button>'
    } else {
      actionBarContent.value = ""
    }
  })
  watch(
 () => props.clearForm,
  (clearForm) => {
    if (clearForm) {
      console.log("clearForm :>> ", clearForm)
    }
  }
)