Joaquin Leon
Joaquin Leon

Reputation: 51

Button with v-on:click that switches between the classes btn-primary and btn-primary-outline not working

Im working on a button that opens a modal. By default it should have the btn-primary-outline class (Blue text, transparent background, blue border), when clicked it should have the btn-primary class (White text, blue background, blue border). But its not working, the button stays trasparent, the text blue, and all its doing is toggling the blue button border on and off.

HTML:

<button v-on:click="settingsButtonIsActive = !settingsButtonIsActive" 
    class="btn margin-top-half center-block col-xs-12"
    :class="[settingsButtonIsActive ? 'btn-primary' : '', 'btn-primary-outline']">
<strong>{{labels.lblButtonConfiguration}}</strong>
</button>

Controller:

data = {
     settingsButtonIsActive: false
}

I feel like the button doesnt like not having any of those 2 clases defined, but i cant think of any other way to do it.

Upvotes: 0

Views: 745

Answers (3)

Silencesys
Silencesys

Reputation: 565

I would recommend rewriting the code a bit.

First of all, you can write the class name switch as a computed property:

// ... beginning of your .js code
computed: {
    isButtonActive () {
      return this.settingsButtonIsActive ? 'btn-primary' : 'btn-outline-primary'
    }
}
// ... rest of your .js code

then you can merge both class attributes into one and bind it like this:

<button v-on:click="settingsButtonIsActive = !settingsButtonIsActive" 
    :class="['btn', 'margin-top-half', 'center-block', 'col-xs-12', isButtonActiveClass">
  <strong>{{labels.lblButtonConfiguration}}</strong>
</button>

There is also another option, but because you change between two classes, I think a computed property is a much cleaner solution. However, you can achieve same result also with this code:

<button v-on:click="settingsButtonIsActive = !settingsButtonIsActive" 
    :class="['btn', 'margin-top-half', 'center-block', 'col-xs-12', {'btn-primary': isButtonActiveClass}, {'btn-outline-primary': !isButtonActiveClass}">
  <strong>{{labels.lblButtonConfiguration}}</strong>
</button>

Note that when I want to change classes dynamically I'm passing an object into the array.

More can be found on https://v2.vuejs.org/v2/guide/class-and-style.html.

Upvotes: 1

Ezra Siton
Ezra Siton

Reputation: 7781

Your "mistake" you use an array syntax but the logic of "else" is empty '' (If settingsButtonIsActive is false render => '') + always render btn-primary-outline (The (ternary) operator inside 0 index - btn-primary-outline on 1 index).

For example this:

:class="[settingsButtonIsActive ? 'btn-primary' : '', 'btn-primary-outline', 'hello', 'world']">

render:

<button class="btn-primary btn-primary-outline hello world">

Not in "vue" this is your logic:

var element = document.getElementById("myDIV");

if(settingsButtonIsActive){
  element.classList.add("btn-primary");
}
else{
  element.classList.add(""); 
}

element.classList.add("btn-primary-outline");

This is the correct markup (For -or- a -or- b) - shortcut for "if else":

class="settingsButtonIsActive ? 'btn-primary' : 'btn-primary-outline'">

No need her for array syntax: https://v2.vuejs.org/v2/guide/class-and-style.html#Array-Syntax

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator

var app = new Vue({
  el: '#app',
  data: {
    msg: "settingsButtonIsActive",
    settingsButtonIsActive: true,
    isActive: "btn-primary",
    hasError: "btn-primary-outline"
  }
})
button{
  padding: 5px;
  cursor: pointer;
}
.btn-primary{
  background: red;
  border: 1px solid red;
}

.btn-primary-outline{
  background: transparent;
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<div id="app">
  <button v-on:click="settingsButtonIsActive = !settingsButtonIsActive" 
          :class="settingsButtonIsActive ? 'btn-primary' : 'btn-primary-outline'">
    <strong>{{msg}}</strong>: {{settingsButtonIsActive}}
  </button>
</div>

Upvotes: 1

Joaquin Leon
Joaquin Leon

Reputation: 51

I fixed it by using the object syntax instead of the array syntax.

<button v-on:click="settingsButtonIsActive = !settingsButtonIsActive"
        class="btn margin-top-half center-block col-xs-12"
        :class="{'btn-primary' : settingsButtonIsActive === true, 'btn-primary-outline' : settingsButtonIsActive === false}">
    <strong>{{labels.lblButtonConfiguration}}</strong>
</button>

Upvotes: 0

Related Questions