0

I'm working with the popular vue-select component for a VueJs project. I want to customize a keyDownEvent and looked into the docs to see how to achieve this. I was met with a cryptic example using a combination of modern JS techniques.

<template>
  <v-select
          taggable
          multiple
          no-drop
          :map-keydown="handlers"
          placeholder="enter an email"
  />
</template>

<script>
export default {
  name: 'CustomHandlers',
  data: {
      variableIwantAccessTo: []
  },
  methods: {
    handlers: (map, vm) => ({
      ...map, 50: e => {
        e.preventDefault();
        if( e.key === '@' && vm.search.length > 0 ) {
          vm.search = `${vm.search}@gmail.com`;
        }
      },
    }),
  },
};
</script>

I understand the simple logic within the if block, but I do not understand the combination of techniques used that leads up to it. The main issue I'm having with my custom implementation is losing the context for the this object. I want something like this:

    handlers: (map, vm) => ({
  ...map, 50: e => {
    e.preventDefault();
    if( e.key === '@' && vm.search.length > 0 ) {
      console.log(this.variableIwantAccessTo);
    }
  },

I cannot figure out how to pass it down with this implementation. Here's a ref to the docs: https://vue-select.org/guide/keydown.html#mapkeydown

4
  • Oh, vm is not the Vue instance as I thought. You'd have to change handler: (map, vm) => ({/*...*/}) to handler(map, vm) { return {/*...*/} }, where you'd be able to use this as the Vue instance. Commented Dec 4, 2020 at 6:45
  • I tried this with Eason Yus answers and it registers as undefined even immediately at the start of the first arrow function. Commented Dec 4, 2020 at 6:48
  • I can't help without seeing the code you've tried. Here's a working demo as I described: codepen.io/tony19/pen/ExgPEKV Commented Dec 4, 2020 at 6:51
  • Ah yes, this is how I'd prefer it written as well. I actually just solved it myself right before your post by using function() {} rather than arrow notation. Commented Dec 4, 2020 at 6:53

2 Answers 2

1

as you see ,there're actually two level of functions in the case,the original style of handler function omit {}, so you don't have a place to define a self(reference to this) in the outer function.

in vue component , this in the outer one will point to the component,so we declare self here, then we use self as a closure variance in the inner one.

i guess this will do your trick, try it ,please.

export default {
  name: 'CustomHandlers',
  methods: {
    // handlers: (map, vm) => {
    // if it is arrow function,it can't do the trick 
    // thanks to  Yair Cohen
       handlers(map, vm) {
        const self = this;
        return {
          ...map, 50: e => {
            e.preventDefault();
            if( e.key === '@' && vm.search.length > 0 ) {
              vm.search = `${vm.search}@gmail.com`;
              // self will be this here
              const self2 = self;
            }
          },
        };
    },
  },
};

update: code changed ,outer function from arrow function to normall function,

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

3 Comments

This is still not going to work as the handlers function is an arrow function instead of a regular so this is still undefined there. If you change it to regular function it'll work
yeah you're right, i just made a demo to test my code, i'll edit it in case wrongly guide others.
Shoutout to @YairCohen for breaking down the function and tony19 for providing a working example using 'this'. I eventually came to the result myself after using this answer and recently dealing with this problem on another project. For those who don't already know checkout this section in the docs vuejs.org/v2/guide/instance.html#Instance-Lifecycle-Hooks
1

Let's break down that function:

  1. You are declaring an arrow function called handlers that accepts two arguments named map and vm.

The reason you are losing context is because you are using an arrow function as a method, if you change that arrow function to a regular function you'll be able to access this.

With that being said it seems like it's designed this way on purpose, and from looking at the code I can assume that you should pass the context as the second argument - vm.

  1. You are returning an object: in the first part of the object you are using the spread operator to spread the map argument, from this we can assume that map is also an object and you want to return an object that contains the object map itself. (by using the spread operator, you are essentially merging map into the object you're returning.

The second part of the object you're returning is a property with the name 50, this property is a method which receives an event, calls preventDefault() on that event, then has an if statement, if that if statement passes it assigns vm.search to a certain value.

Since we assumed that vm stands for the context, this is the same as assigning this.search so it's essentially assigning a variable in the context a particular value.

Hope that's more clear now :)

7 Comments

Technically, you don't need this in an event handler. The element this would usually point to is available from the event object that's passed in.
Only if it's a regular function, with an arrow function this will be equal to the this value from the enclosing scope, which in this case is still undefined.
Well, yeah, the this you get in an arrow function is whatever happens to be inherited from context, if it happened to exist. My point is: Don't use this in an event handler; use the event object. There's no need to switch to a regular function.
No there is no self-invoking function after the first arrow function, the parentheses are there because that's how you return an expression with multiple lines. Check this out for more examples on how that works: stackoverflow.com/questions/20824558/…
@YairCohen Not exactly. Rather, it's the arrow function's implicit return for an object literal. The object needs to be wrapped in parentheses so the parser can distinguish it from a block statement.
|

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.