Passing value of style directive to button component in Vuejs

352 Views Asked by At

I want to add padding to the :style directive of my shared button component but for some reasons, the changes aren't showing up on the button.

I tried doing it with 3 ways below to apply the changes but none of them worked. I'm new to Vuejs and not able to find the problem. Any inputs/suggestions would be appreciated.

<Button
          @on-click="currentStep = 2"
          :text= "Next"
          :style="'padding: 12px 15px 12px 15px'"
       />
<Button
          @on-click="currentStep = 2"
          :text= "Next"
          :style="{ padding: '12px 15px 12px 15px' }"
        />
<Button
          @on-click="currentStep = 2"
          :text= "Next"
          :style="myStyle"
        />

and then returning myStyle: { padding: '12px 15px 12px 15px' } in the script for third one.

My Button.vue component looks like this:

<template>
  {{ this.color }}
  <button 
    @click="onClick"
    :disabled="disabled" 
    class="begin-btn"
    :style="backgroundColor + textColor"
  >{{ text }}
  </button>
</template>

<script>
export default {
  name: 'ButtonComponent',
  props: {
    text: String,
    disabled: Boolean,
    width: String,
    bgColor: String,
    txtColor: String,
  },
  data() {
    return {}
  },
  computed: {

    backgroundColor(){
      let bgColor = this.bgColor ? this.bgColor : '#d64ba1'
      return "background: " + bgColor + ';';
    },

    textColor(){
      let textColor = this.txtColor ? this.txtColor : '#ffffff'
      return "color: " + textColor  + ';';
    }
  },
  methods: {
    onClick() {
      this.$emit("onClick");
    },
  },
}
</script>

<style scoped>
.begin-btn {
  justify-content: center;
  align-items: center;
  border: 0px;
  width: 100%;
  height: 44px;
  background: #d64ba1;
  border-radius: 24px;
  font-style: normal;
  font-weight: 700;
  font-size: 16px;
  color: #ffffff;
}
</style>
4

There are 4 best solutions below

1
On BEST ANSWER

You can use same approach as with another properties: define a property for padding and set a default value for in in your component's computed.

<template>
    <button
        @click="onClick"
        :disabled="disabled"
        class="begin-btn"
        :style="backgroundColor + textColor + calculatedPadding"
    >{{ text }}
    </button>
</template>

<script>
export default {
    name: 'ButtonComponent',
    props: {
        text: String,
        disabled: Boolean,
        width: String,
        bgColor: String,
        txtColor: String,
        padding: String
    },
    data() {
        return {}
    },
    computed: {
        calculatedPadding(){
            const paddingString = this.padding || '10px'; // default padding
            return 'padding:' + paddingString + ';';
        },

        backgroundColor(){
            let bgColor = this.bgColor ? this.bgColor : '#d64ba1'
            return "background: " + bgColor + ';';
        },

        textColor(){
            let textColor = this.txtColor ? this.txtColor : '#ffffff'
            return "color: " + textColor  + ';';
        }
    },
    methods: {
        onClick() {
            this.$emit("onClick");
        },
    },
}
</script>

Then, override the padding value with the one you need in another template where you use your component: SomeView.vue

<template>
    <div>
    <ButtonComponent 
        padding="50px 20px" <!-- overriding default padding for our button -->
    ></ButtonComponent>
    </div>
</template>

<script>
import ButtonComponent from '../components/ButtonComponent'

export default {
    // ....
    components:{
        ButtonComponent
    }
    // ....
}
</script>

UPDATE: You don't even need computed for this. Following code also works fine:

<template>
<button
    @click="onClick"
    :disabled="disabled"
    class="begin-btn"
    :style="backgroundColor + textColor + 'padding:'+this.padding"
>{{ text }}</button>
</template>

And then pass the required value to component:

<ButtonComponent bg-color="red" padding="10px 20px 100px 20px"></ButtonComponent>
1
On

Please take a look at following snippet:

const app = Vue.createApp({
  data() {
    return {
      myStyle: { padding: '12px 15px 12px 15px' },
      Next: 'aaaaaa'
    };
  },
})
app.component('myButton', {
  template: `
  <button 
    @click="onClick"
    :disabled="disabled" 
    class="begin-btn"
    :style="backgroundColor + textColor + getPadding "
  >{{ text }}
  </button>
  `,props: {
    text: String,
    disabled: Boolean,
    width: String,
    bgColor: String,
    txtColor: String,
    padding: String
  },
  data() {
    return {}
  },
  computed: {
    getPadding() {
      return 'padding:' + this.padding.padding
    },
    backgroundColor(){
      let bgColor = this.bgColor ? this.bgColor : '#d64ba1'
      return "background: " + bgColor + ';';
    },
    textColor(){
      let textColor = this.txtColor ? this.txtColor : '#ffffff'
      return "color: " + textColor  + ';';
    }
  },
  methods: {
    onClick() {
      this.$emit("onClick");
    },
  },
})
app.mount('#demo')
.begin-btn {
  justify-content: center;
  align-items: center;
  border: 0px;
  width: 100%;
  height: 44px;
  background: #d64ba1;
  border-radius: 24px;
  font-style: normal;
  font-weight: 700;
  font-size: 16px;
  color: #ffffff;
}
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="demo">
  <my-button
    @on-click="currentStep = 2"
    :text="Next"
    :padding="myStyle"
  ></my-button>
</div>

0
On

1、 use className

<Button
          @on-click="currentStep = 2"
          :text= "Next"
          class="btnClass"
       />
::v-deep{
// or other scoped lint
    .btnClass{
    padding: 12px 15px 12px 15px
    }
}

2、 props styleStr

button use

<Button
          @on-click="currentStep = 2"
          :text= "Next"
          styleStr="padding: '12px 15px 12px 15px'; " // or other your style
        />

button

<template>
  {{ this.color }}
  <button 
    @click="onClick"
    :disabled="disabled" 
    class="begin-btn"
    :style="backgroundColor + textColor + styleStr"
  >{{ text }}
  </button>
</template>

<script>
export default {
  name: 'ButtonComponent',
  props: {
    text: String,
    disabled: Boolean,
    width: String,
    bgColor: String,
    txtColor: String,
    styleStr:String,
  },
  data() {
    return {}
  },
  computed: {

    backgroundColor(){
      let bgColor = this.bgColor ? this.bgColor : '#d64ba1'
      return "background: " + bgColor + ';';
    },

    textColor(){
      let textColor = this.txtColor ? this.txtColor : '#ffffff'
      return "color: " + textColor  + ';';
    }
  },
  methods: {
    onClick() {
      this.$emit("onClick");
    },
  },
}
</script>

<style scoped>
.begin-btn {
  justify-content: center;
  align-items: center;
  border: 0px;
  width: 100%;
  height: 44px;
  background: #d64ba1;
  border-radius: 24px;
  font-style: normal;
  font-weight: 700;
  font-size: 16px;
  color: #ffffff;
}
</style>

3、 props style object

<Button
          @on-click="currentStep = 2"
          :text= "Next"
          :styleObj="{padding: '12px 15px 12px 15px'}" 
        />

button

<template>
  {{ this.color }}
  <button 
    @click="onClick"
    :disabled="disabled" 
    class="begin-btn"
    :style="backgroundColor + textColor +styleObj"
  >{{ text }}
  </button>
</template>

<script>
export default {
  name: 'ButtonComponent',
  props: {
    text: String,
    disabled: Boolean,
    width: String,
    bgColor: String,
    txtColor: String,
    styleObj:String,
  },
  data() {
    return {}
  },
  computed: {

    backgroundColor(){
      let bgColor = this.bgColor ? this.bgColor : '#d64ba1'
      return "background: " + bgColor + ';';
    },

    textColor(){
      let textColor = this.txtColor ? this.txtColor : '#ffffff'
      return "color: " + textColor  + ';';
    }
  },
  methods: {
    onClick() {
      this.$emit("onClick");
    },
  },
}
</script>

<style scoped>
.begin-btn {
  justify-content: center;
  align-items: center;
  border: 0px;
  width: 100%;
  height: 44px;
  background: #d64ba1;
  border-radius: 24px;
  font-style: normal;
  font-weight: 700;
  font-size: 16px;
  color: #ffffff;
}
</style>
```
0
On

The way you bind style property is correct, and it should work: see the example here

What is not working in your example is that your Button component has specified another :style binding internally. You cannot have the same property provided both internally and externally. Vue has to pick one and Vue picks the one defined by your component.