3

Can I pass security review using the next code?
I worry about:
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', mouseup);
and
var x = (e.originalEvent && e.originalEvent.x) || e.clientX;
var y = (e.originalEvent && e.originalEvent.y) || e.clientY;


# Some Component helper.js:

mousedown: function(component, data) {
  var id = data.index;
  var target = data.target;
  var list = component.get('v.list')[target];
  component.set('v.dragElement', { id: id, name: list[id].name });

  // Drag()
  var drag = $A.getCallback(function(e) {
    e.preventDefault();
    if(!component.isValid()) return;
    var x = (e.originalEvent && e.originalEvent.x) || e.clientX;
    var y = (e.originalEvent && e.originalEvent.y) || e.clientY;

    component.set('v.dragOptions', {
      top: y - 40 + 'px',
      left: x + 6 + 'px',
      display: 'block',
    });
  });

  // Mouseup()
  var mouseup = $A.getCallback(function(e) {
    if(!component.isValid()) return;

    component.set('v.dragOptions', {
      top: '-9999px',
      left: '-9999px',
      display: 'none',
    });

    component.set('v.dragElement', null );

    document.removeEventListener('mousemove', drag);
    document.removeEventListener('mouseup', mouseup);

    return false;
  });

  document.addEventListener('mousemove', drag);
  document.addEventListener('mouseup', mouseup);
}

1 Answer 1

5

Short Answer:

When Locker is enforced everywhere, the Security Review won't bother at all about this construction. Until then, yes you can do it if you provide a (reasonable) rationale that you are not interfering with other components and also clean up after yourself.

Long Answer:

Try to design your app in such a way as to attach listeners to the DOM elements belonging to your component rather than attaching listeners to other components or elements of the DOM that don't belong to your app.

In certain situations, you can't do this. For example, suppose you want to hide a certain element if the user clicks anywhere outside of it. In some sense, this is a bad design because you may be stealing clicks from other components. But it's a common use case that makes sense in many UI contexts in which the user, by clicking outside of a DOM element, is really intending to send an event to your code ("close this floating box"). So provide a rationale as to why you are not really stealing clicks, or mouse movements, or whatever, and then you can go ahead and do this as long as you handle it properly:

1) Add code to remove the listeners when your component is unrendered in a custom unrender handler. Although listeners attached to your own DOM elements will be deleted when the DOM elements are themselves removed by the framework, this wont happen for listeners that you added to elements not in your component, such as Document or Window, so you need to delete them in your own custom unrender method.

2) For the same reason, please handle the situation of your component being no longer valid by making cmp.isValid() checks and if you are calling framework methods also use the appropriate re-entry mechanism provided by $A.getCallback(). There have been some situations of event handlers attached to window that modify an attribute of a DOM element (say in an animation) that may have been garbage collected, resulting in many exceptions being thrown. Really check that things still exist in the expected state in your async code.

In Locker, the scoping issues go away (but #2 still needs to be handled).

Because at the moment, Locker is not always guaranteed to be enforced everywhere, you still need to write your code so that it works both in and out of Locker. An update will be made in the Requirements Checklist and Lightning Component Security Best Practices when this changes.

6
  • Where I can store the link to handler for using document.removeEventListener('event', handler) in unrender? Can I do so component.handler = handler? Dec 1, 2016 at 15:23
  • Store it either in a aura:attribute or pass helper's method as handler to the event listner.
    – Praveen
    Dec 1, 2016 at 15:51
  • I've seen working examples where the function is in the helper. You can call a helper from a renderer -- See developer.salesforce.com/docs/atlas.en-us.lightning.meta/… "sharing JS code in a component" Dec 1, 2016 at 17:09
  • Can somebody show example for handler wrapped in $A.getCallback(); ? Dec 2, 2016 at 7:59
  • At the moment: helper.js, renderer.js Dec 2, 2016 at 8:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .