Home » vue » Vue: How to switch between displaying input and label with v-if

Vue: How to switch between displaying input and label with v-if

Posted by: admin November 26, 2021 Leave a comment

Questions:

I need to be able to switch between an input field and a label. When the button “Add Location” is clicked (which create a new div), the input field must be visible. But when the div “Expandable” is maximized it must be hidden and the label visible instead!

The input field should only be visible right after the mentioned button is clicked, else the label has to take its place. What is the best way to achieve this? I was thinking about using some sort of toggle since I am using that in other places.

The label and the input field is placed in the div class “switch”.

You can also see the code in this jsFiddle!

Html

 <div id="lotsOfDivs">
    <addingdivs></addingdivs>
</div>

Vue

var gate = 0;

Vue.component('addingdivs', {
    template: `
<div>
    <div id="header">
        <button class="addDiv" type="button" @click="createDiv">ADD LOCATION</button>
    </div>
    <div class="parent" v-for="div in divs" :style=" div.height ? { 'height': div.height }: null">
        <div class="big" v-if="div.expanded" :key="'expanded' + div.id">

        <div class="switch">
        <input type="text" v-if="inputFieldInfo">
                <label class="propertyLabel" v-else>

            <div class="firstChild">
                <button class="done" @click="increaseLimit">INCREASE</button>
            </div>
            <div class="secondChild">
                <button class="done" @click="expand(div)">EXPAND</button>
            </div>
        </div>
        <div class="small" v-else :key="'collapsed' + div.id">
            <button class="done" @click="expand(div)">EXPAND</button>
        </div>
    </div>
</div>
    `,
 data: function() {
        return {

            gate: gate,
            height: "",
            count: 0,
            locationsArr: ["one", "two", "three"],
            divs: [],
            InputFieldInfo: false
        }
    },

    methods: {
        expand: function(div) {
            if (div.expanded) {
                div.expanded = false
              this.height = ''
            } else {
              div.expanded = true
              this.height = '7vh'
            }
        },

        createDiv: function() {

            if (this.count <= gate) {   // Here you can decide how many divs that will be generated

                // this.count++;
                this.divs.push({
                  id: this.count,
                  expanded: true,
                   inputFieldInfo: true,
                  height: '',
                    });
            this.count++
        }},

        increaseLimit: function() {
// Here you can increase the number of divs that it's possible to generate
            gate++;

        }
    }
});

new Vue({

    el: '#lotsOfDivs',
});
Answers:

The template had a few compilation errors:

  • The <label> needs a closing tag (and text content to be useful)
  • The <div class="big"> needs a closing tag
  • The v-if was bound to inputFieldInfo, but that variable was declared as InputFieldInfo (note the uppercase I), but based on your behavior description, this field should be unique per location container, so a single data property like this wouldn’t work (if I understood your description correctly).

Each location container should have a variable to contain the location name (e.g., locationName) and another variable to contain the show/hide Boolean for the <input> and <label> (i.e., inputFieldInfo):

createDiv: function() {
  this.divs.push({
          // ...
          inputFieldInfo: true,
          locationName: ''
        });
}

Then, we could bind div.inputFieldInfo and div.locationName to the <input>. We bind to v-model so that the user’s text is automatically reflected to the div.locationName variable:

<input v-if="div.inputFieldInfo" v-model="div.locationName">

The <label>‘s content should be div.locationName so that it contains the text from the <input> when shown:

<label class="propertyLabel" v-else>{{div.locationName}}</label>

To switch the <input> with the <label> when the expand-button is clicked, we update expand() to set div.inputFieldInfo to false but only when div.locationName is not empty (this gives the user a chance to revisit/re-expand the container to fill in the location later if needed):

expand: function(div) {
  if (div.expanded) {
    div.expanded = false
    if (div.locationName) {
      div.inputFieldInfo = false
    }
    // ...

updated jsfiddle

###

You had some missing closing tags and an error with InputFieldInfo, it should have a lowercase i.

var gate = 0;

Vue.component('addingdivs', {
  template: `
<div>
    <div id="header">
        <button class="addDiv" type="button" @click="createDiv">ADD LOCATION</button>
    </div>
    <div class="parent" v-for="div in divs" :style=" div.height ? { 'height': div.height }: null">
        <div class="big" v-if="div.expanded" :key="'expanded' + div.id">
          <div class="switch">
              <input type="text" v-if="inputFieldInfo">
              <label class="propertyLabel" v-else>Label</label>

              <div class="firstChild">
                  <button class="done" @click="increaseLimit">INCREASE</button>
              </div>
              <div class="secondChild">
                  <button class="done" @click="expand(div)">EXPAND</button>
              </div>
          </div>
        </div>

        <div class="small" v-else :key="'collapsed' + div.id">
            <button class="done" @click="expand(div)">EXPAND</button>
        </div>
    </div>
</div>
    `,
  data: function() {
    return {
      gate: gate,
      height: "",
      count: 0,
      locationsArr: ["one", "two", "three"],
      divs: [],
      inputFieldInfo: true
    }
  },
  methods: {
    expand: function(div) {
        this.inputFieldInfo = false
      if (div.expanded) {
        div.expanded = false
        this.height = ''
      } else {
        div.expanded = true
        this.height = '7vh'
      }
    },
    createDiv: function() {
                this.inputFieldInfo = true
      if (this.count <= gate) { // Here you can decide how many divs that will be generated
        // this.count++;
        this.divs.push({
          id: this.count,
          expanded: true,
          inputFieldInfo: true,
          height: '',
        });
        this.count++
      }
    },

    increaseLimit: function() {
      // Here you can increase the number of divs that it's possible to generate
      gate++;
    }
  }
});

new Vue({

  el: '#lotsOfDivs',
});

You just basically toggle the inputFieldInfo data, whenever each button is pressed.

###

You can do that by using toggle variable like this

Vue.component('addingdivs', {
    template: `
    <div>
       <div>
        <input type="text" v-if="takeinput">
        <label v-if="!takeinput">
        <button @click="toggleInput()">
        </div>
    </div>
    `,

 data: function() {
        return {
            takeinput:true,           
        }
    },

    methods: {
        toggleInput: function(){
            let vm = this;
            vm.takeinput = ( vm.takeinput == true) ? false : true
            }
        }
});

new Vue({

    el: '#lotsOfDivs',
});

In this example, we are just toggeling value of takeinput on click , so according the value either label or input will be showed.

This is very basic exmpale. But you can extend it as your need