Mohammad Taherian
Mohammad Taherian

Reputation: 1694

How to make change in child components dynamically from parent in Vue.js

I have a form that contains some custom components like custom-input, custom-button, etc. in my custom-form component. My custom components (except custom-form) contain a disabled props. I want to set the disabled props to true in all custom components when a submit button is clicked.

I need to do that dynamically and I don't know which custom components are used in a form. I also need to mention that, It is possible that I have more than one form on a page.

How can I handle that?

Here is what I've tried.

--- Main Component ---
<template>
  <div>
    <slot />
  </div>
</template>
<script>
export default {
}
</script>
--- Component1 ---
<template>
  <div>
    <span v-if="!disabled">this is Comp1</span>
  </div>
</template>
<script>
export default {
  props: {
    disabled: {
      type: Boolean,
      default: false
    }
  }
}
</script>
--- Component2 ---
<template>
  <div>
    <span v-if="!disabled">this is Comp2</span>
  </div>
</template>
<script>
export default {
  props: {
    disabled: {
      type: Boolean,
      default: false
    }
  }
}
</script>
--- My directive ---
import Vue from 'vue'

Vue.directive('disable', {
  bind: (el, binding, vnode) => {
    methods.setChildrent(vnode.context.$children, binding.value)
  }
})

const methods = {
  setChildrent(children, value) {
    children.forEach(element => {      
      this.setChildrent(element.$children, value)
      if(element.$options.propsData)
        if ('disabled' in element.$props)
          element.$props.disabled = value
    })
  }
}

--- Page ---
<template>
  <MainComp v-disable="true">
    <Comp1></Comp1>
    <Comp2></Comp2>
  </MainComp>
</template>

<script>
import Comp1 from './Comp1.vue'
import Comp2 from './Comp2.vue'
import MainComp from './MainComp.vue'
import Directives from '../directives/index.js'
export default {
  name: 'HelloWorld',
  components: {
    Comp1,
    Comp2,
    MainComp,
  },
  directives: {
    Directives
  },
  props: {
    msg: String
  },
  methods: {
  },
  mounted() {   
  }
}
</script>

Upvotes: 4

Views: 3366

Answers (2)

Mohammad Taherian
Mohammad Taherian

Reputation: 1694

I solved this issue by the below approach. I don't know if there are any cases that may cause a problem or not but I did some tests and it was fine.

//Component1

<template>
  <div>
    <span v-if="!disabled">this is Comp1</span>
  </div>
</template>
<script>
export default {
  props: {
    disabled: {
      type: Boolean,
      default: false
    }
  }
}
</script>

//Component2

<template>
  <div>
    <span v-if="!disabled">this is Comp2</span>
  </div>
</template>
<script>
export default {
  props: {
    disabled: {
      type: Boolean,
      default: false
    }
  }
}
</script>

//MainComponent

<template>
  <div>
    <slot />
  </div>
</template>
<script>
export default {
  props: {
    disabled: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    disabled(val) {
      this.setChildrenStatus(val)
    }
  },
  methods: {    
    setChildrenStatus(status) {      
      this.$slots.default.forEach(item => {
        if (item.componentOptions && item.componentOptions.propsData) {
          item.componentOptions.propsData['disabled'] = status
        }
      })
    }    
  }
}
</script>

//Mainpage

<template>
  <MainComp :disabled="disabled">
    <Comp1></Comp1>
    <Comp2></Comp2>
    <br>
    <button @click="setDisabled">submit</button>    
  </MainComp>
</template>

<script>
import Comp1 from './Comp1.vue'
import Comp2 from './Comp2.vue'
import MainComp from './MainComp.vue'
export default {
  name: 'HelloWorld',
  components: {
    Comp1,
    Comp2,
    MainComp,
  },
  data() {
    return {
      disabled: false
    }
  },
  props: {
    msg: String
  },
  methods: {
    setDisabled() {
      this.disabled = !this.disabled
    }
  }
}
</script>


Upvotes: 1

digout
digout

Reputation: 4252

Props!

// main component / view

<template>
    <custom-form />
    <custom-form />
</template>

<script>
import CustomForm from './CustomForm'

export default {
    components: { CustomForm },
    data() {
        return {
            disabled: false
        }
    },
    methods: {
        setDisabled() { 
            this.disabled = true
        }
    }
}
</script>

// CustomForm.vue

<template>
    <form @submit.prevent="submit">
        <custom-element :disabled="disabled" />
        <custom-element :disabled="disabled" />
    </form>
</template>

<script>
    import CustomElement from './CustomElement'

    export default {
        data() { 
            return {
                disabled: true
            }
        },
        props: ['disabled'],
        components: { CustomElement },
        methods: {
            submit() {
                this.disabled = true
            }
        }
    }
</script>

// CustomElement.vue

<template>
    <input :disabled="disabled" />
</template>

<script>
    export default {
        props: ['disabled']
    }
</script>

Upvotes: 4

Related Questions