Dynamically set Mousetrap.bind() key combinations from an object

1.3k Views Asked by At

I'm getting back data from our backend that contains information about keyboard shortcuts. This is a dumbed down version of what I will receive:

    { code: "r", message: "test R" },
    { code: "s", message: "test S" },
    { code: "c", message: "test C"}

The 'Code' specifies which key will activate the keyboard shortcut, and the message is what will be pasted in an input box.

I am using the Mousetrap library, which allows me to write functions like so:

Mousetrap.bind('shift+^+r', function () {
    alert("test");
});

My question is: is there a way to write these functions at runtime based on the data brought back? So for every item in the JSON object, a function will be needed to handle the shortcut.

I've tried this:

    var html = document.getElementById("shortcuts").innerHTML;
    document.getElementById("shortcuts").innerHTML = html + "<script> Mousetrap.bind('shift+^+r', function () { alert('test) })); <\/script>"

I don't know if this is good practice, as I am still quite new to JS, but this was the only thing I could come up with. It doesnt work though.

2

There are 2 best solutions below

6
On BEST ANSWER

Sure. Sounds easy enough. Just create a separate function accepting an object, getting both the code and message properties and calling Mousetrap.bind(str, func) on runtime

function bindKey(input){
    const code = input.code;
    const message = input.message;

    const bindStr = "shift+^+" + code; //idk if you need shift here but modify as needed

    Mousetrap.bind(bindStr, function(){
          alert(message);
    });
}

Use via

bindKey({code: "r", message: "test R"});
bindKey({code: "c", message: "test C"});
bindKey({code: "d", message: "test D"});

If you have an array of objects, just loop through them and call bindKey()

myArray.forEach(bindKey);
// or
for (const i of myArray) bindKey(i);

No need to write a script element. Just write the function and call it on runtime. Why you need to render a script tag is beyond me.


Test below

function bindKey(input){
   const code = input.code;
   const message = input.message;

   const bindStr = "shift+^+" + code; //idk if you need shift here but modify as needed
    
    Mousetrap.bind(bindStr, function(){
          console.log(message);
    });
}
    
bindKey({code: "r", message: "test R"});
bindKey({code: "c", message: "test C"});
bindKey({code: "d", message: "test D"});
<script src="https://craig.global.ssl.fastly.net/js/mousetrap/mousetrap.min.js"></script>

5
On

You can iterate through all the objects, upon binding the key with code from each object you can search through the array and pick the element to display the message. Modest implementation:

var data = [{code:"r",message:"test R"},{code:"s",message:"test S"},{code:"c",message:"test C"}];

//use forEach to go through each item in data
data.forEach(key => {
  //call MouseTrap bind on key.code, key is one of the element in data
  Mousetrap.bind('shift+^+' + key.code, (e) => {
    //e is the event variable from the keystroke
    
    //data.find will find the element which has the key value(e.key) from the event
    //converting into lowercase because data is in lowercase too
    var element = data.find(d => {
      //check if code of the element matches e.key
      if (d.code == e.key.toLowerCase()) return d;
    });
    //log element.message
    console.log(element.message);
  });
});
<script src="https://craig.global.ssl.fastly.net/js/mousetrap/mousetrap.min.js"></script>


Suggestion from @Bergi, @AZ_:

var data = [{code:"r",message:"test R"},{code:"s",message:"test S"},{code:"c",message:"test C"}];

data.forEach(({code, message}) => Mousetrap.bind(`shift+^+${code}`, () => console.log(message)));
<script src="https://craig.global.ssl.fastly.net/js/mousetrap/mousetrap.min.js"></script>