[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.javascript

eventDispath how that work

Une Bévue

10/14/2014 2:24:00 PM

Iv' tried eventDispatch but doesn't understand how it works really.

Say, in my html i have a paragraphe :
<p id='elem'>Listening to 'build' event...</p>

it listen to the CustomEvent 'build' :
elem.addEventListener('build', function (e) {
console.log("'elem' listener: event.type = " + event.type);
console.log("'elem' listener: event.detail = " + event.detail);
},
false
);

next, i have a button 'test' :
<button id='test' data-date='14 oct 2014'>sendTest</button>
which listen to two events :
test.addEventListener('click', sendTest, false);
test.addEventListener('build', receiveBuildTest, true);

when the click event occurs the function sendTest create a new event and
dispatch it :
function sendTest(e) {
console.log("sendTest(e) e:");
console.dir(e);
event = new CustomEvent('build', { 'detail': e.target.dataset.date });
e.target.dispatchEvent(event);
}

well this new event is received by the 'test' element in the function
receiveBuildTest :
function receiveBuildTest(e) {
console.log("receiveBuildTest(e) e:");
console.dir(e);
}

BUT the paragraphe element 'elem' does not receive this event even if it
listen to by :
elem.addEventListener('build', function (e) {
console.log("'elem' listener: event.type = " + event.type);
console.log("'elem' listener: event.detail = " + event.detail);
},
false
);


Why ?

In fact i don't understand why this event could only be recived on the
element who has generated it, not interesting...

as far as i understand...

What i want to do :

send an event to other parts of the dom from one having receive one from
user click, by example.
19 Answers

JJ

10/14/2014 8:25:00 PM

0

On Tue, 14 Oct 2014 16:23:39 +0200, Une Bévue wrote:

> Iv' tried eventDispatch but doesn't understand how it works really.
>
> Say, in my html i have a paragraphe :
> <p id='elem'>Listening to 'build' event...</p>
>
> it listen to the CustomEvent 'build' :
> elem.addEventListener('build', function (e) {
> console.log("'elem' listener: event.type = " + event.type);
> console.log("'elem' listener: event.detail = " + event.detail);
> },
> false
> );
>
> next, i have a button 'test' :
> <button id='test' data-date='14 oct 2014'>sendTest</button>
> which listen to two events :
> test.addEventListener('click', sendTest, false);
> test.addEventListener('build', receiveBuildTest, true);
>
> when the click event occurs the function sendTest create a new event and
> dispatch it :
> function sendTest(e) {
> console.log("sendTest(e) e:");
> console.dir(e);
> event = new CustomEvent('build', { 'detail': e.target.dataset.date });
> e.target.dispatchEvent(event);
> }
>
> well this new event is received by the 'test' element in the function
> receiveBuildTest :
> function receiveBuildTest(e) {
> console.log("receiveBuildTest(e) e:");
> console.dir(e);
> }
>
> BUT the paragraphe element 'elem' does not receive this event even if it
> listen to by :
> elem.addEventListener('build', function (e) {
> console.log("'elem' listener: event.type = " + event.type);
> console.log("'elem' listener: event.detail = " + event.detail);
> },
> false
> );
>
> Why ?
>
> In fact i don't understand why this event could only be recived on the
> element who has generated it, not interesting...
>
> as far as i understand...
>
> What i want to do :
>
> send an event to other parts of the dom from one having receive one from
> user click, by example.

Because dispatchEvent() trigger the event only on the element and its child
elements. So you need to call dispatchEvent() of the "elem" element object.
i.e.:

e = document.querySelector("#elem");
e.dispatchEvent(event);

Une Bévue

10/15/2014 8:50:00 AM

0

Le 14/10/14 22:24, JJ a écrit :
> Because dispatchEvent() trigger the event only on the element and its child
> elements. So you need to call dispatchEvent() of the "elem" element object.
> i.e.:
>
> e = document.querySelector("#elem");
> e.dispatchEvent(event);

OK, ok, fine, thanks !

Thomas 'PointedEars' Lahn

10/15/2014 1:25:00 PM

0

JJ wrote:

> On Tue, 14 Oct 2014 16:23:39 +0200, Une Bévue wrote:
>> function sendTest(e) {
>> console.log("sendTest(e) e:");
>> console.dir(e);
>> event = new CustomEvent('build', { 'detail': e.target.dataset.date
>> }); e.target.dispatchEvent(event);

You need to write

var event = â?¦;

or you could accidentally access (and perhaps overwrite) the built-in
â??eventâ? property of the Window object of the global execution context, which
likely is in the scope chain.

> e = document.querySelector("#elem");

Avoid this newer, less compatible, less efficient pattern, and replace it
with

e = document.getElementById("elem");

You also need to declare â??eâ?. Otherwise â?? often discussed here before â?? the
code will not run in strict mode and will cause side-effects in non-strict
mode:

var e;

Declaration and initialization can be combined:

var e = document.getElementById("elem");

(Likewise, when you are tempted to write

document.querySelector(".foo")

then write

document.getElementsByClassName("foo")

instead. [Of course, you still need to make sure that
Document::getElementsByClassName() is implemented. Usually you would use a
wrapper method instead that falls back to an implementation of
Document::getElementsByTagName("*").])

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not Cc: me. / Bitte keine Kopien per E-Mail.

JJ

10/15/2014 7:10:00 PM

0

On Wed, 15 Oct 2014 15:24:48 +0200, Thomas 'PointedEars' Lahn wrote:
> You need to write
>
> var event = !K;
>
> or you could accidentally access (and perhaps overwrite) the built-in
> !§event!? property of the Window object of the global execution context, which
> likely is in the scope chain.

Yes. I should have mentioned that my code snippet is in sendTest() context.
Sorry about that.

>> e = document.querySelector("#elem");
>
> Avoid this newer, less compatible, less efficient pattern, and replace it
> with
>
> e = document.getElementById("elem");

Well, in this case getElementById() would be much more efficient.

> You also need to declare !§e!?. Otherwise !V often discussed here before !V the
> code will not run in strict mode and will cause side-effects in non-strict
> mode:
>
> var e;
>
> Declaration and initialization can be combined:
>
> var e = document.getElementById("elem");

Since my code was meant to be placed within sendTest(), i.e.:

function sendTest(e) {
console.log("sendTest(e) e:");
console.dir(e);
event = new CustomEvent('build', { 'detail': e.target.dataset.date });

e = document.querySelector("#elem");
e.dispatchEvent(event);
}

This is fine I presume? Cause AFAIK, the x variables of these two functions
are both local.

function f1() {
var x;
x = 1;
}
function f2(x) {
x = 1; //this won't refer to any scope-inherited x variable
}

Or is there a potential problem with this?

> (Likewise, when you are tempted to write
>
> document.querySelector(".foo")
>
> then write
>
> document.getElementsByClassName("foo")
>
> instead. [Of course, you still need to make sure that
> Document::getElementsByClassName() is implemented. Usually you would use a
> wrapper method instead that falls back to an implementation of
> Document::getElementsByTagName("*").])

I guess I got too accustomed on using querySelector(). :P
Better optimize my UserScripts then...

Une Bévue

10/15/2014 8:06:00 PM

0

Le 15/10/14 15:24, Thomas 'PointedEars' Lahn a écrit :
> You need to write
>
> var event = â?¦;
>
> or you could accidentally access (and perhaps overwrite) the built-in
> â??eventâ? property of the Window object of the global execution context, which
> likely is in the scope chain.


I posted :

event = ...

because this part of the script is "inside" another function.

clearly i have :

var elem, event, test, body;
____________^^^^^____________ // out of any function then belongs to
window object.

actually the elements listening to this event are :

document, body, test (the button who fired this event), para (a
paragraphe) and i've added a pre (log).

for the time being only document, body, test are receiving this event,
the paragraphe named para (a <p />) and a <pre /> named log aren't
receiving this event the html structure is :

<html>
<head />
<body>
<p id='para'>...
<button id='test' data-date='14 oct 2014'>sendTest</button>
<div><pre id='log' ...
</body>
</html>

the event 'event' is fired from sendTest() itself actionned by the click
over the only button :
test.addEventListener('click', sendTest, false);

Then clearly, what said "JJ" :
> Because dispatchEvent() trigger the event only on the element and its child
> elements.

is not right because document and body did received the event and body
and document aren't child of test who fired this event.


In fact I've found a workaround using some modified version of @author
Erik Karlsson, www.nonobtrusive.com "class" Dispatcher().

And this works very well talking into account suggestions of Aubrey
Taylor <http://pastie.org/191... and Tobias
<http://pastie.org/297541... i can now dispatch event to any element
regardless of the node structure.


Thomas 'PointedEars' Lahn

10/15/2014 9:03:00 PM

0

JJ wrote:

> On Wed, 15 Oct 2014 15:24:48 +0200, Thomas 'PointedEars' Lahn wrote:
>>> e = document.querySelector("#elem");
>>
>> Avoid this newer, less compatible, less efficient pattern, and replace it
>> with
>>
>> e = document.getElementById("elem");
>
> Well, in this case getElementById() would be much more efficient.

AISB.

>> You also need to declare â??eâ?. Otherwise â?? often discussed here before â??
>> the code will not run in strict mode and will cause side-effects in
>> non-strict mode:
>>
>> var e;
>>
>> Declaration and initialization can be combined:
>>
>> var e = document.getElementById("elem");
>
> Since my code was meant to be placed within sendTest(), i.e.:
>
> function sendTest(e) {
> console.log("sendTest(e) e:");
> console.dir(e);
> event = new CustomEvent('build', { 'detail': e.target.dataset.date
> });
>
> e = document.querySelector("#elem");
> e.dispatchEvent(event);
> }
>
> This is fine I presume?

No, given just this code, â??eventâ? is neither declared a variable in
sendTest(), nor is it the identifier of a formal parameter. It would
therefore refer to the â??eventâ? property of the next object in the scope
chain that has it, it would be considered an attempt to augment the global
object with an â??eventâ? property in non-strict mode, or, because no object in
the scope chain had such a property, it would throw a ReferenceError
exception in strict mode.

You would probably see a kind of runtime error caused by the inability to
overwrite a property of a host object in MSHTML-based runtime environments
(e.g., Internet Explorer), and a ReferenceError exception in strict mode
elsewhere.

Also, one should avoid reusing formal parameters as if they were local
variables. In this case, there is the additional caveat of accessing host
objects in perhaps unforeseen ways: â??eâ? would refer to one, an event object
(as indicated by â??e.targetâ?; I am not sure about any browser-based host
object having a built-in â??datasetâ? property either, so there is potentially
an unforeseen *write* access to avoid before).

Incidentally, at work today I encountered, essentially, this piece of code
written by someone else:

if (window.toString.call(â?¦) == "[object Array]") {
// â?¦
}

(Obviously an attempt to detect whether an value would be a reference to an
Array instance, which is in many cases a misguided one [see â??duck typingâ?
for details].)

It failed reproducibly in Internet Explorer 8 (with the infamous â??error code
0â?) on Windows XP¹ because there was no â??window.toStringâ?, and that caused
*other* code (a progress indicator) to not function (a JScript/MSHTML
peculiarity).

For now, I can see three possible explanations how this code came about
(I will investigate this tomorrow morning):

A. Someone declared a global â??toStringâ? function or variable, and
attempted to access the global object through â??windowâ?.

B. Someone attempted to assign a reference to a Function instance to a
previously non-existing â??toStringâ? property of the object referred to
by â??windowâ?.

C. Someone thought â??windowâ? would refer to the native ECMAScript global
object and would therefore have a built-in â??toStringâ? method.

Either way, that someone *must* have been unaware² that the (*host-defined*)
â??windowâ? property (of the ECMAScript global object) does _not_, in general,
refer to the ECMAScript global object, but to a *host* object that already
has properties (some with setters), and neither needs to admit augmentation
nor does it need to inherit native methods like Object.prototype.toString().

______
¹ the oldest version we need to support for this application
² probably blissfully, likely through bad books and/or bad tutorials like
w3schools.com

> Cause

Non sequitur.

> AFAIK, the x variables of these two functions are both local.
>
> function f1() {
> var x;
> x = 1;
> }
> function f2(x) {
> x = 1; //this won't refer to any scope-inherited x variable
> }

Correct, except that the latter â??xâ? is the identifier of a formal parameter,
_not_ a local variable.

> Or is there a potential problem with this?

Only that these examples do not fully apply to sendTest().

>> (Likewise, when you are tempted to write
>>
>> document.querySelector(".foo")
>>
>> then write
>>
>> document.getElementsByClassName("foo")

Correction: The latter would be equivalent to

document.querySelectorAll(".foo")

Instead,

document.getElementsByClassName("foo")[0]

would be equivalent to the former, provided that the method returned a
reference to an object implementing the NodeList or HTMLCollection interface
(which would need to be tested before the â??0â? property read access).

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not Cc: me. / Bitte keine Kopien per E-Mail.

Thomas 'PointedEars' Lahn

10/15/2014 9:39:00 PM

0

Une Bévue wrote:

> Le 15/10/14 15:24, Thomas 'PointedEars' Lahn a écrit :
>> You need to write
>>
>> var event = â?¦;
>>
>> or you could accidentally access (and perhaps overwrite) the built-in
>> â??eventâ? property of the Window object of the global execution context,
>> which likely is in the scope chain.
>
>
> I posted :
>
> event = ...
>
> because this part of the script is "inside" another function.

Non sequitur. There is no good (obvious) reason why you should declare
â??eventâ? outside of the function, and every (obvious) reason to declare it
local, inside. In fact, the code that you posted at first â??

elem.addEventListener('build', function (e) {
console.log("'elem' listener: event.type = " + event.type);
console.log("'elem' listener: event.detail = " + event.detail);
},
false
);

â?? *cannot* work without â??eventâ? referring to an object (or a value
convertible to one) *before* the listener is called (which does not make
sense). [It has a chance to work with â??var event = (typeof e ==
"undefined") ? window.event : e;� as first statement of the function.]

> clearly i have :
>
> var elem, event, test, body;
> ____________^^^^^____________ // out of any function then belongs to
> window object.

First of all, you had not posted this declaration before, and all our
crystal balls are as b0rken as is the From header field value of your
postings (which you want to fix before your next posting).

Second, why do you declare that many global variables? The rule of thumb is
to declare as few global variables as reasonably possible in order to avoid
â??spoiling the global namespaceâ?.

> actually the elements listening to this event are :
>
> document, body, test (the button who fired this event), para (a
> paragraphe) and i've added a pre (log).

In general, you do not need to declare global variables for elements that
have listeners added for an event. In fact, you want to avoid that because
of potential memory leaks.

> for the time being only document, body, test are receiving this event,
> the paragraphe named para (a <p />) and a <pre /> named log aren't
> receiving this event the html structure is :
>
> <html>
> <head />

Invalid, see <http://validator.w....

> <body>
> <p id='para'>...
> <button id='test' data-date='14 oct 2014'>sendTest</button>
> <div><pre id='log' ...

A â??buttonâ? element inside a â??pâ? element? A â??preâ? element inside a â??divâ?
element? Really?

> Then clearly, what said "JJ" :
>> Because dispatchEvent() trigger the event only on the element and its
>> child elements.
>
> is not right

Yes, indeed.

> because document and body did received the event and body
> and document aren't child of test who fired this event.

Yes, dispatchEvent() dispatches custom events as any other event is
dispatched. It depends on the event (bubbling or not; cancelable and not
canceled, or not) and the listeners (capturing or not) in which dispatch
phase (capturing or bubbling), if any, the event can be handled.

<http://www.w3.org/TR/DOM-Level-3-Events/#even...

> In fact I've found a workaround using some modified version of @author
> Erik Karlsson, www.nonobtrusive.com "class" Dispatcher().

Oh my.

> And this works very well talking into account suggestions of Aubrey
> Taylor <http://pastie.org/191... and Tobias
> <http://pastie.org/297541... i can now dispatch event to any element
> regardless of the node structure.

For suitable values of â??very wellâ?. You are blissfully unaware of the low
quality of the code that you are using.

BTW, in English you need to write the standalone pronoun â??Iâ? with a capital
letter *always*, and in general no space is written before punctuation.

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not Cc: me. / Bitte keine Kopien per E-Mail.

JR

10/15/2014 9:59:00 PM

0

On 15/10/2014 18:02, Thomas 'PointedEars' Lahn wrote:
> Correction: The latter would be equivalent to
>
> document.querySelectorAll(".foo")
>
> Instead,
>
> document.getElementsByClassName("foo")[0]
>
> would be equivalent to the former, provided that the method returned
> a reference to an object implementing the NodeList or HTMLCollection
> interface (which would need to be tested before the â??0â? property read
> access).

Pardon me, but these methods are not equivalent because:

a) The getElementsByClassName() method returns a live NodeList whereas
querySelectorAll() returns a static NodeList;

b) The getElementsByClassName() method excludes any elements that are
not descendants of the HTMLElement object on which the method was
invoked. However, even though the querySelectorAll() method is invoked
on an element, selectors are still evaluated in the context of the
entire document. For instance, the querySelectorAll() method will still
match the div element's child p element, even though the body element is
not a descendant of the div element itself.

var div = document.getElementById("bar");
var p = div.querySelector("body p");


ref:
<http://www.w3.org/TR/2008/WD-html5-20080610/dom.html#getelementsbycla...
<http://www.w3.org/TR/selectors...

--
Joao Rodrigues

Thomas 'PointedEars' Lahn

10/16/2014 12:49:00 AM

0

Joao Rodrigues wrote:

> On 15/10/2014 18:02, Thomas 'PointedEars' Lahn wrote:
>> Correction: The latter would be equivalent to
>>
>> document.querySelectorAll(".foo")
>>
>> Instead,
>>
>> document.getElementsByClassName("foo")[0]
>>
>> would be equivalent to the former, provided that the method returned
>> a reference to an object implementing the NodeList or HTMLCollection
>> interface (which would need to be tested before the â??0â? property read
>> access).
>
> Pardon me, but these methods are not equivalent because:
>
> a) The getElementsByClassName() method returns a live NodeList whereas
> querySelectorAll() returns a static NodeList;

ACK.

> b) The getElementsByClassName() method excludes any elements that are
> not descendants of the HTMLElement object on which the method was
> invoked.

Your logic is flawed. getElementsByClassName() was not invoked on an object
implementing the HTMLElement interface here; it was invoked on an object
implementing the (HTML)Document interface. That is a separate method, as
even your own references say.

> [â?¦]
> var div = document.getElementById("bar");
> var p = div.querySelector("body p");

So this example does not apply here in two respects:

1. another method
2. another selector

> <http://www.w3.org/TR/2008/WD-html5-20080610/dom.html#getelementsbycla...
> <http://www.w3.org/TR/selectors...

Again you have referred to a Working Draft and a Working Group Note, which
both are non-normative, although a Proposed Recommendation and a
Recommendation, respectively, are available.

<http://www.w3.org/TR/2014/PR-html5-20140916/infrastructure.html#common-dom-inte...

refers to

<http://www.w3.org/TR/dom/#do...

and thus

<http://www.w3.org/TR/dom/#dom-document-getelementsbycla...

and

<http://www.w3.org/TR/dom/#dom-parentnode-queryselec...

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not Cc: me. / Bitte keine Kopien per E-Mail.

Une Bévue

10/16/2014 12:27:00 PM

0

Le 15/10/14 23:39, Thomas 'PointedEars' Lahn a écrit :
>> <head />
> Invalid, see<http://validator.w....
>

obviously it was a "symbolic" way to shortened the code...

> as is From header field value of your
> postings (which you want to fix before your next posting)

The From header is due to Thunderbird 24.6.0, what is wrong with that ?

Anyway, I rewrote my code:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>dispatch-event</title>
<script>
var build_event;
window.onload = function(e) {
console.log("window.onload");
build_event = new CustomEvent("build", {
detail: {
message: 'toto',
time: new Date(),
},
bubbles: true,
cancelable: true
});
test.addEventListener('click', sendTest, false);
test = document.getElementById('test');
document.addEventListener('build', documentReceiveBuildTest, true);
document.body.addEventListener('build', bodyReceiveBuildTest, true);
document.getElementById('para').addEventListener('build',
paraReceiveBuildTest, true);
}
function documentReceiveBuildTest(e) {
console.log("documentReceiveBuildTest(e) event.type = " + event.type);
return true;
}
function bodyReceiveBuildTest(e) {
console.log("bodyReceiveBuildTest(e) event.type = " + event.type);
return true;
}
function paraReceiveBuildTest(e) {
console.log("paraReceiveBuildTest(e) event.type = " + event.type);
return true;
}
function sendTest(e) {
console.log("sendTest(e)");
document.body.dispatchEvent(build_event);
}
</script>
</head>
<body>
<p id='para'>Listening to 'build' event...</p>
<button id='test' data-date='16 oct 2014'>sendTest</button>
</body>
</html>

in the console log I got:
window.onload
sendTest(e)
documentReceiveBuildTest(e) event.type = build
bodyReceiveBuildTest(e) event.type = build


Then, the "<p id='para'>Listening to 'build' event...</p>" still doesn't
received this "build_event", and i still don't know why and where is my
error.
This time, this is the body :
document.body.dispatchEvent(build_event);
firing the event, then the "<p id='para'>Listening to 'build'
event...</p>" is clearly a child of it.