17

I'm playing with vue.js for learning purposes consisting of different components, one of them being a classic to do list. For now, everything is within one component.

I want to change the text of a button after it is clicked to hide an element from "hide" to "show" - I'm going about this by setting a text data object and then changing it in a function.

See below:

<div id="app">
  <ul>
    <li v-for="todo in todos">
      {{ todo.text }}
    </li>
  </ul>

  <input type="text" id="list-input">
  <input type="submit" id="list-submit" v-on:click="addItem">
  <span id="error" style="color: red; display: none;">Please Enter Text</span>

  <ul>
    <todoitem></todoitem>
    <todoitem></todoitem>
    <todoitem></todoitem>
  </ul>

  <h2 v-if="seen">SEEN</h2>
  <button id="hide-seen" v-on:click="toggleSeen">{{ button.text }}</button>
</div> 

<script type="text/javascript">
// components
Vue.component('todoitem', {
  template: "<li>Test Item</li>"
})

// app code
var app = new Vue({
  el: '#app',
  data: {
    todos: [
      { text: 'Sample Item 1' },
      { text: 'Sample Item 2' },
      { text: 'Sample Item 3' }
    ],
    button: [
      { text: 'Hide'}
    ],
    seen: true
  },
  methods: {
    addItem: function() {
      let item = document.getElementById("list-input").value;
      let error = document.getElementById("error");
      if (item == "") {
        error.style.display = "block";
      } else {
        app.todos.push({ text: item });
        error.style.display = "none";
      }
    },
    toggleSeen: function() {
      app.seen = false
      app.button.push({ text: 'Show' });
    }
  }
})


</script>

Unexpectedly, the button is blank on both hide and show states. Being new to vue, this seems like a strange way to go about doing it. Is changing data in this context bad practice? I don't understand how to fix this, as I have no errors in my console.

1
  • Why is your button data property an array? Commented Oct 4, 2017 at 14:33

2 Answers 2

12

Here you have your code in a snipplet.

I change your button by a plain object instead of an array and small adaptation in method toggleSeen.

// components
Vue.component('todoitem', {
  template: "<li>Test Item</li>"
})

// app code
var app = new Vue({
  el: '#app',
  data: {
    todos: [
      { text: 'Sample Item 1' },
      { text: 'Sample Item 2' },
      { text: 'Sample Item 3' }
    ],
    button: {
      text: 'Hide'
    },
    seen: true
  },
  methods: {
    addItem: function() {
      let item = document.getElementById("list-input").value;
      let error = document.getElementById("error");
      if (item == "") {
        error.style.display = "block";
      } else {
        app.todos.push({ text: item });
        error.style.display = "none";
      }
    },
    toggleSeen: function() {
      app.seen = !app.seen;
      app.button.text = app.seen ? 'Hide' : 'Show';
    }
  }
});
<script src="https://vuejs.org/js/vue.min.js"></script>

<div id="app">
  <ul>
    <li v-for="todo in todos">
      {{ todo.text }}
    </li>
  </ul>

  <input type="text" id="list-input">
  <input type="submit" id="list-submit" v-on:click="addItem">
  <span id="error" style="color: red; display: none;">Please Enter Text</span>

  <ul>
    <todoitem></todoitem>
    <todoitem></todoitem>
    <todoitem></todoitem>
  </ul>

  <h2 v-if="seen">SEEN</h2>
  <button id="hide-seen" v-on:click="toggleSeen">{{ button.text }}</button>
</div>

Sign up to request clarification or add additional context in comments.

2 Comments

This is good and solves the problem! However I'm having trouble understanding the line app.seen = !app.seen can you explain what is happening there? So you're just setting an opposite condition on every event? I read that as app.seen is being assigned the opposite condition - is that the gist of it?
app.seen is a boolean value, so equal to true or false. ! is operator to inverse condition result. If condition result is true, then false is return and if condition result is false, true is return. That is same to do if(app.seen == true) { app.seen = false; } else { app.seen = true; }
6

You can achieve this by using refs in vuejs:

<body>
    <div id = 'app'>
        <button @click="changeState" ref="btnToggle">Hide</button>
        <div v-show="show">
            <h1>1 to 100</h1>
            <p v-for="i in 100">{{i}}</p>
        </div>
    </div>
    <script>
        const app = new Vue({
            el:'#app',
            data: function(){
                return{
                    show: true
                }
            },
            methods: {
                changeState: function(){
                    this.show = !this.show;
                    this.$refs.btnToggle.innerText = this.show?'Hide':'Show';

                }
            },
        });
    </script>
</body>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.