skip to Main Content

I have this function that returns either true or false that is created in a child component. And this child component is called inside a nuxt page. It’s like this:

Child component

<template>
  <div>
    <h2 class="font-bold text-2xl text-white">Select Your Role</h2>
    <p class="text-gray-90 my-2">
      Select your role that fit most with your needs
    </p>
    <div>
      <div class="flex gap-3">
        <div
          class="flex items-center gap-3 border border-dark-60 p-3 rounded-lg"
        >
          <label class="cursor-pointer" for="1">SEO Specialist</label>
          <input
            id="1"
            v-model="selectedRole"
            class="opacity-60"
            type="radio"
            value="SEO Specialist"
          />
        </div>
        <div
          class="flex items-center gap-3 border border-dark-60 p-3 rounded-lg"
        >
          <label for="2">Content Writer</label>
          <input
            id="2"
            v-model="selectedRole"
            class="opacity-60"
            type="radio"
            value="Content Writer"
          />
        </div>
        <div
          class="flex items-center gap-3 border border-dark-60 p-3 rounded-lg"
        >
          <label for="3">Product Manager</label>
          <input
            id="3"
            v-model="selectedRole"
            class="opacity-60"
            type="radio"
            value="Product Manager"
          />
        </div>
      </div>
      <div class="flex gap-3 my-3">
        <div
          class="flex items-center gap-3 border border-dark-60 p-3 rounded-lg"
        >
          <label for="4">Business Owner</label>
          <input
            id="4"
            v-model="selectedRole"
            class="opacity-60"
            type="radio"
            value="Business Owner"
          />
        </div>
        <div
          class="flex items-center gap-3 border border-dark-60 p-3 rounded-lg"
        >
          <label for="5">Freelancer</label>
          <input
            id="5"
            v-model="selectedRole"
            class="opacity-60"
            type="radio"
            value="Freelancer"
          />
        </div>
        <div
          class="flex items-center gap-3 border border-dark-60 p-3 rounded-lg"
        >
          <label for="6">SEO / Marketing Agency</label>
          <input
            id="6"
            v-model="selectedRole"
            class="opacity-60"
            type="radio"
            value="SEO / Marketing Agency"
          />
        </div>
      </div>
      <div class="flex gap-3">
        <div
          class="flex items-center gap-3 border border-dark-60 p-3 rounded-lg"
        >
          <label for="7">Product Marketing Manager</label>
          <input
            id="7"
            v-model="selectedRole"
            class="opacity-60"
            type="radio"
            value="Product Marketing Manager"
          />
        </div>
        <div
          class="flex items-center gap-3 border border-dark-60 p-3 rounded-lg"
        >
          <cm-input placeholder="Other"></cm-input>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'SelectPosition',

  data() {
    return {
      selectedRole: '',
      otherRole: '',
    }
  },
  methods: {
    methods: {
      isValid() {
        this.$emit('update:valid', false)
      },
    },
  },
}
</script>

Page file as parent

<template>
  <div class="w-full">
    <div class="flex flex-col">
      <div class="container grid grid-cols-12 gap-8 mx-auto p-12">
        <div class="col-span-3"></div>
        <div class="col-span-6">
          <h1 class="font-bold text-3xl text-white">Setting Up the Crawler</h1>
          <p class="text-gray-60 col-span-6">
            Lorem ipsum dolor sit, amet consectetur adipisicing elit. Tempora
            maiores suscipit doloremque!
          </p>
        </div>
      </div>

      <RegisterProgressBar :value="step" :max="5" />

      <div class="container grid grid-cols-12 gap-8 mx-auto p-12">
        <div class="col-span-3 gap-20 mx-3">
          <transition name="fade-in" mode="out-in">
            <div
              class="flex flex-col gap-4 border border-dark-60 rounded-lg h-[200px] max-h-48 items-center mx-11"
            >
              <img
                src="https://www.gravatar.com/avatar/078a5f992a23c763d83473ebeb359c6d.jpg?d=identicon&s=200"
                width="40"
                height="40"
                alt="team picture"
                class="mt-3"
              />
              <div class="flex flex-col items-center gap-1">
                <h3 class="text-lg font-bold">{{ team_name }}</h3>
                <p>{{ domain_label }}</p>
              </div>
              <cm-tooltip>
                <template #toggler>
                  <span class="underline"> What's this? </span>
                </template>
                <span class="dark:text-dark-80">
                  This is a pre-defined team name for you. You can change the
                  name later in the settings.
                </span>
              </cm-tooltip>

              <div
                v-if="keywords.length !== 0"
                class="flex justify-center rounded-lg p-4 mt-3 bg-dark-90 text-gray-60 w-full text-left"
              >
                <div class="flex flex-col gap-1 text-left">
                  <div>
                    <cm-icon class="bx bx-key" />
                    <span class="mx-3 underline">Keywords</span>
                    <span class="font-bold">{{ keywords.length }}</span>
                  </div>
                  <div v-if="selectedCountry.length !== 0">
                    <cm-icon class="bx bx-building" />
                    <span class="mx-3 underline">Countries</span>
                    <span class="font-bold">{{ selectedCountry.length }}</span>
                  </div>
                  <div v-if="selectedLanguage.length !== 0">
                    <cm-icon class="bx bx-user-voice" />
                    <span class="mx-3 underline">Languages</span>
                    <span class="font-bold">{{ selectedLanguage.length }}</span>
                  </div>
                  <div v-if="device.length !== 0">
                    <cm-icon class="bx bx-devices" />
                    <span class="mx-3 underline">Devices</span>
                    <span class="font-bold">{{ device.length }}</span>
                  </div>
                </div>
              </div>
            </div>
          </transition>
        </div>
        <div class="flex flex-col col-span-6">
          <transition name="fade-in" mode="out-in">
            <component :is="currentStepComponent" />
          </transition>
          <div class="flex gap-3 self-end mt-3">
            <cm-button v-if="step > 1" variant="gray" contextual @click="back"
              >Prev</cm-button
            >
            <cm-button variant="gray" :disabled="isValid">Next</cm-button>
          </div>
        </div>
        <div class="col-span-3"></div>
      </div>
    </div>
  </div>
</template>

<script>
import { mapState } from 'vuex'
import appConfig from '~/config/globals/appConfig'

import RegisterProgressBar from '~/components/new-register/ProgressBar.vue'
import SelectPosition from '~/components/new-register/SelectPosition.vue'
import SelectPlan from '~/components/new-register/SelectPlan.vue'

export default {
  name: 'UserPosition',

  auth: 'guest',

  components: {
    RegisterProgressBar,
    SelectPosition,
    SelectPlan,
  },

  layout: 'new-register/default2',

  data() {
    return {
      team_name: JSON.parse(localStorage.getItem('app.registration.data'))
        .team_name,
      domain_label: JSON.parse(localStorage.getItem('app.registration.data'))
        .domain_label,
      step: 2,
    }
  },
  computed: {
    ...mapState('registration', {
      domain: 'domain',
      keywords: 'keywords',
      selectedLanguage: 'selectedLanguage',
      selectedCountry: 'selectedCountry',
      device: 'device',
    }),
    currentStepComponent() {
      switch (this.step) {
        case 1:
          return 'SelectPosition'
        case 2:
          return 'SelectPosition'
        case 3:
          return 'SelectPlan'
        case 4:
          return 'SelectLanguage'
        case 5:
          return 'SelectDevice'
        default:
          return ''
      }
    },
  },

  methods: {
    back() {
      this.step--
    },

    next() {
      this.step++
      this.submit()
    },

    submit() {
      try {
        console.log({
          ...this.registrationData,
          position: 'selectedRole',
        })
        this.$storage.setUniversal(appConfig.app.registration, {
          ...this.registrationData,
          position: 'selectedRole',
        })
        this.$cmToast({
          title: 'Data stored successfully!',
          icon: 'bx-info-circle',
          variant: 'success',
        })
      } finally {
        this.isLoading = false
      }
    },
  },
}
</script>

In short I want to make the next button to be disabled if both selectedRole and otherRole data is empty string.

2

Answers


  1. You have to take this custom-event on child component like and also I think you should name your custom event as updateValid and also from button component your value in update:valid is undefined you must pass a correct value

    <button :isDisabled="isValid" @updateValid="changeValidVal"></button>
    

    and after this you can create a method also I’m guessing you want change the value of isValid so you can do that in this func

    changeValidVal(val){
      this.isValid = val
    }
    
    Login or Signup to reply.
  2. I didn’t solve this one, but I figured another way by using vuex instead of props.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search