0

The task is the same as in this post: capture click on a link and prevent the browser's default behavior. The answer given there was this:

Template:

<a on-click='sayHello' href="#">Activate!</button>

JS:

ractive.on( 'sayHello', function ( event ) {
  event.original.preventDefault();
  alert( 'Hello world!' );
});

The problem is that the sayHello event handler should not know about what the original event was. The whole point of proxying is that the event handler should not care about the type of the original event. For example, I change the link into a button, there's no more need for preventDefault.

So, my question is how I can invoke preventDefault before or after firing the event proxy.

A nice solution would be to fire several event proxies in a row (if it was possible):

Template:

<a on-click='preventDefault;sayHello' href="#">Activate!</button>

Js:

ractive.on( 'preventDefault', function ( event ) {
  event.original.preventDefault();
});
ractive.on( 'sayHello', function ( event ) {
  alert( 'Hello world!' );
});

Is this possible somehow? Or is there some other nice solution?

Community
  • 1
  • 1
Bernát
  • 1,362
  • 14
  • 19

3 Answers3

1

One approach might be to pass an argument that determines whether the default should be prevented:

template:

<a on-click='sayHello:true' href="#">Activate!</a>
<button on-click='sayHello'>Activate!</button>

code:

ractive.on( 'sayHello', function ( event, shouldPreventDefault ) {
  if ( shouldPreventDefault ) {
    event.original.preventDefault();
  }
  alert( 'Hello world!' );
});

Or, if you wanted to avoid the boolean trap you could do...

<a on-click='sayHello:{preventDefault:true}' href="#">Activate!</a>

...et cetera.

Chaining events is an interesting idea. I'm not convinced it belongs in the library, but you could certainly do something like

template:

<a on-click='multiple:["preventDefault","sayHello"]' href='#'>Activate!</a>

code:

ractive.on( 'multiple', function ( event, sequence ) {
  var eventName, i, len;

  len = sequence.length;
  for ( i = 0; i < len; i += 1 ) {
    this.fire( sequence[i], event );
  }
});

This pattern could be expanded upon to include arguments if needed.

Rich Harris
  • 28,091
  • 3
  • 84
  • 99
  • 1
    `sequence.shift` will affect the actual sequence specified in the attribute, i.e. second time the event is fired, sequence will be empty. To avoid this problem you need to iterate through the list without clearing it (e.g. use `for` loop) – tnajdek Apr 28 '14 at 14:27
0

I solved it this way, but I'm not totally satisfied.

Template:

<a on-click='pd_and:sayHello' href="#">Activate!</button>

Js:

ractive.on( 'pd_and', function ( event, next ) {
  event.original.preventDefault();
  var i = args.indexOf(':'), arg;
  if (i === -1) {
    type = next;
    arg = undefined;
  } else {
    type = next.substr(0, i);
    arg = next.substr(i + 1);
  }
  return ractive.fire(type, event, arg);

});
Bernát
  • 1,362
  • 14
  • 19
0

If your goal is to encapsulate the preventDefault between template and method, then you can roll your own proxy event:

Ractive.events.clickpd = function ( node, fire ) {
    node.addEventListener('click', click)

    function click(e){
        e.preventDefault()
        fire({ 
           node: node,  //breaks Ractive if not included
           original: e  //optional
        })
    }
    return { 
        teardown: function () {
            node.removeEventListener('click', click)
        } 
    }
}

And use it like so:

<a on-clickpd='sayGreeting'>{{greeting}}</a>

See http://jsfiddle.net/ka2Pu/2/ for full example.

Docs on custom events are here: http://docs.ractivejs.org/latest/ractive-events

martypdx
  • 3,702
  • 14
  • 22