valtro05
valtro05

Reputation: 81

Object Value Returning 'Undefined' in Array in vue.js

I am trying to better myself at JavaScript OOP, and I'm learning vue.js as well. I am building a simple task list to teach myself, and I have most of it done except for the remove task function. I originally was just using the .remove() option, but it was not updating my v-if and v-else statement on my front end, even with another function checking the length of the array. So, I decided to try and splice my array, but I'm a bit lost since it's returning undefined. As each element in the array is an object, I'm sure it's the way I'm trying to call the value, but I'm not too sure how to do so.

Here is the HTML:

<div class="form-group">

      <input type="text" id='task-entry' class='px-2' @keyup.enter="addTask">
      <a href="#" class='btn btn-info' id='task-button' @click="addTask">Add Task</a>

    </div> <!-- form-group -->

    <hr class='hr my-5 bg-dark'>

    <div class="task-list py-3 bg-white mx-auto w-75">

      <ul v-if='taskList.length > 0' class='mb-0 px-2'>

        <li v-for="tasks in taskList" class='text-dark p-3 task-item text-left clearfix'>
          <div class='task-name float-left'>
              <span>{{ tasks.task }}</span>
          </div>

          <a href="#" class="btn btn-danger remove-task float-right" @click='removeTask'>Remove Task</a>

        </li>

      </ul>

      <div v-else>
        You currently have no tasks.
      </div>

And here is the JavaScript:

new Vue({
  el: '#app',
  data: {
    title: 'To Do List',
    taskList: [],
    showError: false
  },
  methods: {
    addTask: function () {

      var task = document.getElementById('task-entry');

      if (task.value !== '' && task.value !== ' ') {
        this.error(1);
        this.taskList.push({
          task: task.value
        });
        task.value = '';
      } else {
        this.error(0);
      }
    },
    removeTask: function (e) {
      if(e.target.classList.contains('remove-task')) {

        var targetElement = e.target.parentElement;

        var test = targetElement.querySelector('span').innerText;

        console.log(test);
        console.log(this.taskList[{task: test}]);

      } else {
        e.preventDefault;
      }
    },
    error: function (value) {
      if (value === 0) {
        this.showError = true;
      } else {
        this.showError = false;
      }
    }
  }
});

Upvotes: 3

Views: 6022

Answers (2)

Tu Nguyen
Tu Nguyen

Reputation: 10179

Try this: (I implement the remove function in VueJS way, it's really simple)

new Vue({
  el: '#app',
  data: {
    title: 'To Do List',
    taskList: [],
    showError: false
  },
  methods: {
    addTask: function() {
      var task = document.getElementById('task-entry');
      if (task.value !== '' && task.value !== ' ') {
        this.error(1);
        this.taskList.push({
          task: task.value
        });
        task.value = '';
      } else {
        this.error(0);
      }
    },
    removeTask: function(tasks) {
      this.taskList.splice(this.taskList.indexOf(tasks), 1)
    },
    error: function(value) {
      if (value === 0) {
        this.showError = true;
      } else {
        this.showError = false;
      }
    }
  }
});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

<div id="app">
  <div class="form-group">
    <input type="text" id='task-entry' class='px-2' @keyup.enter="addTask">
    <a href="#" class='btn btn-info' id='task-button' @click="addTask">Add Task</a>
  </div>
  <!-- form-group -->
  <hr class='hr my-5 bg-dark'>
  <div class="task-list py-3 bg-white mx-auto w-75">
    <ul v-if='taskList.length > 0' class='mb-0 px-2'>
      <li v-for="tasks in taskList" class='text-dark p-3 task-item text-left clearfix'>
        <div class='task-name float-left'>
          <span>{{ tasks.task }}</span>
        </div>
        <a href="#" class="btn btn-danger remove-task float-right" @click='removeTask(tasks)'>Remove Task</a>
      </li>
    </ul>
    <div v-else>
      You currently have no tasks.
    </div>
  </div>


There are two small steps to make your code work as expected:

S1: In the template change the event handler to @click='removeTask(tasks)', like this:

<a href="#" class="btn btn-danger remove-task float-right" @click='removeTask(tasks)'>Remove Task</a>

S2: In the script, re-write the remove method like so:

removeTask: function(tasks) {
   this.taskList.splice(this.taskList.indexOf(tasks), 1)
}

Upvotes: 2

Phil
Phil

Reputation: 164812

There's a much more Vue-specific way to go about what you're trying to achieve and you definitely don't need to be querying the DOM for values.

Let's start with your removeTask method.

Array.prototype.splice() uses an index to remove / insert values from an array. You can get this index from v-for using something like

<li v-for="(tasks, index) in taskList">

Now your remove link can use this index

<a @click.prevent="removeTask(index)">

and your method can use

removeTask (index) {
  this.taskList.splice(index, 1)
}

For adding tasks, I recommend using v-model to bind the new task to your input, eg

<input type="text" v-model="newTask" @keyup.enter="addTask">

and

data: {
  title: 'To Do List',
  taskList: [],
  showError: false,
  newTask: '' // added this
},
methods: {
  addTask () {
    if (this.newTask.trim().length > 0) {
      this.error(1)
      this.taskList.push({ task: this.newTask })
      this.newTask = ''
    } else {
      this.error(0)
    }
  }
}

Upvotes: 1

Related Questions