Refactoring template events


#1

Right now I am trying to refactor my events.

I have a template for a list of items. Each item has multiple attributes.
What each event does is when a person is typing in an input, it’ll update the item’s attribute in the collection when the key is up.

The problem is that I have similar events 3 times. Hoping for a suggestion that could help me learn to improve the code I have so far.

HTML file:

<template name="listItem">
<li>
	<input type="text" value="{{attr1}}" name="attr1"> 
	<input type="text" value="{{attr2}}" name="attr2">
	<input type="number" value="{{attr3}}" name="attr3">
</li>
</template>

Javascript file:

Template.listItem.events({
  'keyup [name=attr1]': function(event){
    if(event.which == 13 || event.which == 27) {
      event.target.blur();
    } else {
      var documentId = this._id;
      var attr1 = event.target.value;
      List.update({ _id: documentId }, {$set: { attr1: attr1 }});
    }
  },

  'keyup [name=attr2]': function(event){
    if(event.which == 13 || event.which == 27) {
      event.target.blur();
    } else {
      var documentId = this._id;
      var attr2 = event.target.value;
      List.update({ _id: documentId }, {$set: { attr2: attr2 }});
    }
  },

  'keyup [name=attr3]': function(event){
    if(event.which == 13 || event.which == 27) {
      event.target.blur();
    } else {
      var documentId = this._id;
      var attr3 = event.target.value;
      List.update({ _id: documentId }, {$set: { attr3: attr3 }});
    }
  },
});

#2

I am switched to coffeescript now, but I would use something like this

function keyPushed(event, docId) {
  if(event.which == 13 || event.which == 27) {
      $(event.target).blur();
    } else {
      var specialAttr = $(event.target).val();
      List.update({ _id: docId }, {$set: { event.target.name: specialAttr }});
    }
}

Template.listItem.events({
  'keyup input': function(event){
    keyPushed(event, this._id);
  }
});

And of course I would debounce it, cause you dont want to update it for every letter while typing fast
edit3: And I dont understand why you are jquery style targeting event parameters, cause you already have all that data in event object… but I just copied your style a little.


#3

Thank you for taking the time to respond to me, Shock.

Right now, I was just working on the minimum to make sure it worked. I didn’t even think about how I was writing in jquery style and was going to work on debouncing later. I hope that my small updates look fine for now.

Anyway I have attempted your suggestion and altered it slightly. I created a variable to store event.target.name because of received an error in the console. Besides that, it “seems” to run fine (no errors in the console), except my collections isn’t actually updating. Do you have any idea why that might be the case?


I ended up writing the following in my template events. The problem is that I do not understand why the commented out line does not work, but the eval line does work.

  'keyup input': function(event){
    if(event.which == 13 || event.which == 27) {
      $(event.target).blur();
    } else {
      var documentId = this._id;
      var attr = event.target.name;
      var attr_input = event.target.value;
      // TODO: Figure out why this line doesn't work
      // List.update({ _id: documentId }, {$set: { attr: attr_input }});
      eval("List.update({_id:'"+documentId+"'}, {$set: {"+attr+":'"+attr_input+"'}})");
    }
  }

#4
var modifier = {};
modifier[attr] = attr_input;
List.update({ _id: documentId }, {$set: modifier});

#5

Make it shorter:

if ('13,27').match(event.which) {}

#6

I haven’t tested, but the main idea is to create separate template:

<template name="listItem">
  <li>
    {{> listItem__input name='attr1' docId=_id value=attr1 type='text'}}
    {{> listItem__input name='attr2' docId=_id value=attr2 type='text'}}
    {{> listItem__input name='attr3' docId=_id value=attr3 type='number'}}
  </li>
</template>

<template name="listItem__input" input="name value type docId">
  <input
    type="{{type}}"
    value="{{value}}"
    name="{{name}}"
  >
</template>
Template.listItem__input.events({
  'keyup': function(e) {
    var target = e.target,
        key = e.which,
        query;

    if (key === 13 || key === 27) {
      target.blur();
    } else {
      query = { $set: {} }
      query.$set[this.name] = target.value;
      List.update(this.docId, query);
    }
  },
})