1

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.

Abana Clara
  • 4,602
  • 3
  • 18
  • 31
Mahogany
  • 509
  • 4
  • 17
  • 2
    No, don't "write a function". Don't create a ` – Bergi Jul 18 '19 at 10:40
  • You might want to accept AbanaClara's answer, which is just what I would've written – Bergi Jul 18 '19 at 10:45
  • @Bergi Upon giving that comment more thought, I was thinking how I would then call that for each item in the array. As there would need to be multiple variables; one for each item. – Mahogany Jul 18 '19 at 10:46
  • Just loop over the array and call `bindKey` with each item. – Bergi Jul 18 '19 at 10:48

2 Answers2

3

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>
Abana Clara
  • 4,602
  • 3
  • 18
  • 31
  • 2
    @Plastic I did. `document.write` and creating functions from ` – Bergi Jul 18 '19 at 10:44
  • @Bergi, you are totally right, and i delete my answer, I was just pointing that in the way he tried to append the script to the page it will never run. By the way, you should always try to argue a downvote. – Plastic Jul 18 '19 at 10:46
  • Thanks for this answer. Why I need to render a script tag is beyond me too, it was just the first thing that came to mind, so thanks for teaching me that it's bad practice. – Mahogany Jul 18 '19 at 10:49
  • I don't seem to able to get this working. When using bindKey for each of the items in the array, thats the only time the method is called. When actually pressing the shortcuts, nothing happens. – Mahogany Jul 18 '19 at 10:56
  • @Mahogany I mistyped the string format for the Mousetrap library. Fixed and included a working snippet – Abana Clara Jul 18 '19 at 10:59
  • Great, thats working now. @shrys's answer is working too. Which would you recommend using? – Mahogany Jul 18 '19 at 11:02
2

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>
shrys
  • 5,860
  • 2
  • 21
  • 36
  • Wow, this is working brilliantly. Could you possible explain how this is working for a novice? – Mahogany Jul 18 '19 at 10:47
  • 1
    You'll want to use `find`, not `filter`, and you'll want to return a boolean from the callback. But why search the `data` at all? You already have the object with the `.message` in the `key` variable. – Bergi Jul 18 '19 at 10:47
  • @shrys Perfect, thank you. Currently yours is working the best, will leave this for a few hours and then accept an answer. – Mahogany Jul 18 '19 at 10:56
  • @Mahogany kewl kewl – shrys Jul 18 '19 at 10:57
  • 4
    As @Bergi said what's the point of researching the element from array, only `data.forEach(({code, message}) => Mousetrap.bind(\`shift+^+${code}\`, () => console.log(message)))` is enough – AZ_ Jul 18 '19 at 11:16