1

i have problem with input and lists, I would like to go through from input to list element below and add class 'active' to current li element

<div class="control">
      <label class="label">Input Test</label>
      <input type="text" class="input" @keydown="keyHandler">
      <ul>
        <li v-for="suggestion in suggestions" v-bind:class="{active}">{{suggestion.message}}</li>
      </ul>
    </div>

methods : {
    keyHandler(e){
        if(e.keyCode === 38){
        e.preventDefault();
        console.log('arrow up')
        this.currentKey = e.key
      }
      else if(e.keyCode === 40){
        e.preventDefault();
        console.log('arrow down')
        this.currentKey = e.key
      }
    }   
  }

here is fiddle: https://jsfiddle.net/o8fwf0gh/13/

I would be grateful for help

2 Answers 2

4

Hope this helps.

var app = new Vue({
  el: '#form',
  data: {
    currentKey: null,
    suggestions: [{
      message: 'Foo'
    }, {
      message: 'Bar'
    }, {
      message: 'Foobar'
    }, {
      message: 'pikachu'
    }, {
      message: 'raichu'
    }],
    active: false
  },
  methods: {
    keyHandler(e) {
        if (e.keyCode === 38) {
          e.preventDefault();
          console.log('arrow up')
          this.setActiveClass(this.currentKey, e.key)
          this.currentKey = e.key
        } else if (e.keyCode === 40) {
          e.preventDefault();
          this.setActiveClass(this.currentKey, e.key)
          console.log('arrow down')
          this.currentKey = e.key
        }
      },
      setActiveClass(previousKey, currentKey) {
        if (previousKey) {
          var tempIndex = this.suggestions.findIndex(x => x.class ==     "active");
          this.$set(this.suggestions[tempIndex], 'class', 'inactive')
          if (currentKey === 'ArrowDown') {
            if (tempIndex === this.suggestions.length - 1)
              this.$set(this.suggestions[0], 'class', 'active')
            else
              this.$set(this.suggestions[tempIndex + 1], 'class', 'active')
          } else {
            if (tempIndex === 0)
              this.$set(this.suggestions[this.suggestions.length - 1], 'class', 'active')
            else
              this.$set(this.suggestions[tempIndex - 1], 'class',     'active')
          }
        } else {
          if(currentKey === 'ArrowUp')
            this.$set(this.suggestions[this.suggestions.length - 1], 'class', 'active')
          else
            this.$set(this.suggestions[0], 'class', 'active')
          }
        }
      }
  }
})

and in HTML you can do the following:

<li v-for="suggestion in suggestions" v-bind:class='suggestion.class'>{{suggestion.message}}

Working example here

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

3 Comments

That is perfect! Thanks
could you tell me how to change your fiddle when the data is suggestions: [ 'Foo', 'Bar', 'Foobar', 'pikachu', 'raichu'], here is fiddle: jsfiddle.net/o8fwf0gh/19 I get the "Cannot create property 'class' on string" error
The method I have used works only when you have array of objects. Now you have changed it to array of strings. So solution does not hold for your new requirement.
1

What you could do is update a data property, let's say selected, with where you should be in the list. By default we'll set it on 0, so that the first element is selected:

data: {
    selected: 0,
    // other data stuff
}

When pressing the up or down arrow you obviously have to update this.selected as such:

methods : {
keyHandler(e){
    if(e.keyCode === 38){
        e.preventDefault();
        this.selected--;
    }
    else if(e.keyCode === 40){
        e.preventDefault();
        this.selected++;
    }
}   

}

You can then set up your list as such:

<li v-for="(suggestion, index) in suggestions" :class="index === selected ? 'active' : ''">{{suggestion.message}}</li>

What you see inside the class property is know as shorthand syntax. It's basically an if statement that returns 'active' if the index is equal to the list-number that is currently selected. As you can see the index is passed along as a second property inside v-for.

This should do the trick, if I understood correctly what you're trying to achieve. :P

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.