Event.observe and the element reference

0 views
Skip to first unread message

Thierry

unread,
Dec 17, 2007, 5:49:22 PM12/17/07
to Ruby on Rails: Spinoffs
Just a quick question about the element parameter to Event.observe, in
prototype 1.6.0 ...

I'm used to DOM scripting, and I'm wondering if a behavior of
prototype is intentional or not.
When the documentation says
"The DOM element you want to observe; as always in Prototype, this
can be either an actual DOM reference, or the ID string for the
element."
and I try to give it a DOM element node, I get the error "element has
no properties"...
The localized function where this happens is:

function getEventID(element) {
if (element._eventID) return element._eventID; //<= The error
happens here...
arguments.callee.id = arguments.callee.id || 1;
return element._eventID = ++arguments.callee.id;
}

Now, If I add an id on the node, and I give this id to observe(),
everything works just fine, but can we use the DOM element, or just
the HTML element after having fetched it's reference through $()?

For more understanding, this is where I had this issue.
I scan my DOM tree at load time, to find every js:ajax attributes on
form elements.
When I find one, I want to add the handler to replace the standard GET/
POST mechanism with an Ajax.Request() call, binded to the form.
So, I have in my HTML:
<form action="/actions/login" method="post" js:ajax="on">
...
</form>

And my JS object prototype is as follow:
ajaxFrm.prototype={
init:function(e){
var aryFrms=document.getElementsByTagName('form');
var elm;
var i=0;
var att=null;
for(i=0;i<aryFrms.length;i++){
elm=aryFrms[i];
att=elm.getAttribute('js:ajax');
if(att!==null && att.toLowerCase()!=='off'){
//Apply an ajax request rather than the original form
elm.pars="ajax=true&amp;hash="+this.hash;

//We process the return of the request
elm.process=function(req){
alert(req.responseText);
}

elm.doCall=function(e){
var elm=e.elment();
elm.req=new new Ajax.Request( elm.action, {
method: 'post',
parameters: elm.pars,
onComplete: elm.process
}
);
}

//We add the onSubmit event handler
Event.observe(elm,'submit', elm.doCall);

//we get every input except the submit
var aryInp=elm.getElementsByTagName('input');
for(var j=0;j<aryInp.length;j++){
if(
(aryInp[j].type.toLowerCase()!='submit')
&&
(aryInp[j].type.toLowerCase()!='file')
){
if(pars.length>0){
pars+="&amp;";
}
elm.pars+=aryInp[j].name+"="+aryInp[j].value;
}
}
}
}
}
}

So, I try to add an event observer on the DOM node elm, which is a
shortcut to the element fetched through getElementsByTagName() ad I
get this error.
As I said, if I add an id on the forms, and address the element via
this id, it works, so it's no big deal to me, as I just have to
remember to put an id on every elements I want to observe, but this
looks a bit overkill to me.
Or am I using it the wrong way.

Thanks.
Thierry.

Fabio

unread,
Dec 17, 2007, 7:30:55 PM12/17/07
to Ruby on Rails: Spinoffs
It should work with a DOM element...

Maybe it's a problem with this line:
var elm=e.elment();

Thierry

unread,
Dec 17, 2007, 8:35:17 PM12/17/07
to Ruby on Rails: Spinoffs
On 18 déc, 01:30, Fabio <fabiow...@gmail.com> wrote:
> It should work with a DOM element...
>
It would seem logical to mee too.
But then, is there a distinction between an DOM node and a DOM
element ?
> Maybe it's a problem with this line:
> var elm=e.elment();
>
No, the problem appeared when I added
Event.observe(elm,'submit', elm.doCall);
And as I specified, if I replace elm with elm.id and give the foem an
id, it works.
But it just seem a bit strange to me, as elm is already a reference to
a dom element.

The elm.element() line is the function that will be tied to the form
and trigerred on the form submit.
That code in the previous post is in fact a rearranged snippet of
several methods, compiled in 1 bigger, but clearer.
I might have broken something when re-arranging it.

Wizz

unread,
Dec 18, 2007, 8:41:51 AM12/18/07
to Ruby on Rails: Spinoffs
It seems to me like prototype doesn't extend it if you pass the
element and it does if you pass the id...

Give this a try:

Event.observe($(elm),'submit', elm.doCall);

What fabio was trying to point out that that line has a typo...

var elm=e.elment(); // should be: var elm=e.element();

Greetz,

Wizz

Thierry

unread,
Dec 18, 2007, 9:36:37 AM12/18/07
to Ruby on Rails: Spinoffs
On Dec 18, 2:41 pm, Wizz <woutaw...@gmail.com> wrote:
> It seems to me like prototype doesn't extend it if you pass the
> element and it does if you pass the id...
>
> Give this a try:
>
> Event.observe($(elm),'submit', elm.doCall);
>
Hmm, interesting... I didn't thought of that.
I'm at work now, I'll give it a try later, thanks.

> What fabio was trying to point out that that line has a typo...
>
> var elm=e.elment(); // should be: var elm=e.element();
Yeah, saw it later.
It hitted just now, that it was what he was pointing me to.
sorry Fabio.

In the meantime (and my lunch break) I continued coding that piece of
js, and completed it, using id's to reference the forms.
It looks like it works great, but it's still very much untested.

Thanks anyway for the suggestion, I'll post the result here later
tonight.

Cheers.
Thierry.

> Greetz,
>
> Wizz

Fabio

unread,
Dec 18, 2007, 9:41:44 AM12/18/07
to Ruby on Rails: Spinoffs
It shouldn't be necessary (to pass $(elm)), since every element passed
as argument is extended right after the function begins ( the
statement element = $(element) is always present).

Check this example:
<body>
<div>DIV</div>
<script>
var div = document.getElementsByTagName('div')[0];
Event.observe(div, 'click', function(){
alert('here');
});
</script>
</body>

In any case, you could always call 'observe' like this:
$(div).observe('click', function...);


Wizz escreveu:

> It seems to me like prototype doesn't extend it if you pass the
> element and it does if you pass the id...
>
> Give this a try:
>
> Event.observe($(elm),'submit', elm.doCall);
>
> What fabio was trying to point out that that line has a typo...
>
> var elm=e.elment(); // should be: var elm=e.element();
>
> Greetz,
>
> Wizz
>
> On Dec 18, 2:35 am, Thierry <tsch...@gmail.com> wrote:
> > On 18 d�c, 01:30, Fabio <fabiow...@gmail.com> wrote:> It should work with a DOM element...

Thierry

unread,
Dec 18, 2007, 11:06:26 AM12/18/07
to Ruby on Rails: Spinoffs


On Dec 18, 3:41 pm, Fabio <fabiow...@gmail.com> wrote:
> It shouldn't be necessary (to pass $(elm)), since every element passed
> as argument is extended right after the function begins ( the
> statement element = $(element) is always present).
>
> Check this example:
> <body>
> <div>DIV</div>
> <script>
> var div = document.getElementsByTagName('div')[0];
> Event.observe(div, 'click', function(){
> alert('here');});
>
> </script>
> </body>
>
> In any case, you could always call 'observe' like this:
> $(div).observe('click', function...);

I tried it, but it don't work:

var btn=document.createElement('input');
btn.type="button";
btn.className=aryInp[cptInp].className;
btn.value=aryInp[cptInp].value;
btn.frm=elm;
btn.id=Math.random();
btn.setAttribute('rel','ajax');

//And we replace our original button
aryInp[cptInp].parentNode.replaceChild(btn, aryInp[cptInp]);
//Event.observe(btn.id,'click',elm.doCall); //This is ok, as I'm
referencing btn's via it's id
btn.observe('click', elm.doCall); //this fails, with the same error
as before: element has no properties :: if (element._eventID) return
element._eventID;
Event.observe($(btn),'click',elm.doCall); //this fails too, with the
same error.

You can see it live, on http://dating.webalis.com/?LNG=fr
The procedure is trigerred when you click the "go!" button on the top
left login box.
If js is disabled, it's a standard form, which post to a url.
With js enabled, I replace the submit button with a simple button
which launch an ajax request on the same url, but with different
parameters.
The return handler is still plain dumb, as it just alert() the xml
fragment returned by the server.

I've tried the Event.observe(elm,...) call with prototype 1.6.0 and
1.5.1.1 Both have the same behavior and fail the same way.
I would have tried the svn version too if I had rails installed at my
work computer....

Anyway, I've got it running, so it's no big deal, but I'm still
wondering if I don't do something wrong....

Cheers.
Thierry.

Nicolás Sanguinetti

unread,
Dec 18, 2007, 11:13:02 AM12/18/07
to rubyonrail...@googlegroups.com
On Dec 18, 2007 12:41 PM, Fabio <fabi...@gmail.com> wrote:
>
> It shouldn't be necessary (to pass $(elm)), since every element passed
> as argument is extended right after the function begins ( the
> statement element = $(element) is always present).

Yeah, but it seems it has its problems, I was looking into this post
yesterday and stumbled some very weird behavior when using
Event.observe with unextended nodes:
http://groups.google.com/group/prototype-core/t/abd86333d12601f2

Nicolas :-\

Nicolás Sanguinetti

unread,
Dec 18, 2007, 11:32:12 AM12/18/07
to rubyonrail...@googlegroups.com
On Dec 18, 2007 2:06 PM, Thierry <tsc...@gmail.com> wrote:
>
>
>
> On Dec 18, 3:41 pm, Fabio <fabiow...@gmail.com> wrote:
> > It shouldn't be necessary (to pass $(elm)), since every element passed
> > as argument is extended right after the function begins ( the
> > statement element = $(element) is always present).
> >
> > Check this example:
> > <body>
> > <div>DIV</div>
> > <script>
> > var div = document.getElementsByTagName('div')[0];
> > Event.observe(div, 'click', function(){
> > alert('here');});
> >
> > </script>
> > </body>
> >
> > In any case, you could always call 'observe' like this:
> > $(div).observe('click', function...);
>
> I tried it, but it don't work:
>
> var btn=document.createElement('input');
> btn.type="button";
> btn.className=aryInp[cptInp].className;
> btn.value=aryInp[cptInp].value;
> btn.frm=elm;
> btn.id=Math.random();
> btn.setAttribute('rel','ajax');

Please, while you're using Prototype, *use* Prototype :)

var original = $(aryInp[cptInp]);
var btn = new Element("input", { type: "button", className:
original.className, rel: "ajax" }).setValue( $F(original) );
btn.identify();

original.replace(btn);
btn.observe('click', elm.doCall);

By using plain old DOM methods you will surely stumble into
cross-browser issues, plus, wrting the code with Prototype will make
it much more concise and easier to follow :)

> //And we replace our original button
> aryInp[cptInp].parentNode.replaceChild(btn, aryInp[cptInp]);
> //Event.observe(btn.id,'click',elm.doCall); //This is ok, as I'm
> referencing btn's via it's id
> btn.observe('click', elm.doCall); //this fails, with the same error
> as before: element has no properties :: if (element._eventID) return
> element._eventID;
> Event.observe($(btn),'click',elm.doCall); //this fails too, with the
> same error.
>
> You can see it live, on http://dating.webalis.com/?LNG=fr
> The procedure is trigerred when you click the "go!" button on the top
> left login box.
> If js is disabled, it's a standard form, which post to a url.
> With js enabled, I replace the submit button with a simple button
> which launch an ajax request on the same url, but with different
> parameters.
> The return handler is still plain dumb, as it just alert() the xml
> fragment returned by the server.

If you're only trying to intercept the submit of the form in order to
do it via ajax, replacing the submit button is *not* the best way to
do it, as people can still submit the form "normally" by hitting enter
when focusing a form field. Instead, hijack the form's 'submit' event:

$("the_form_id").observe("submit", function(event) {
event.stop(); // this prevents the 'regular' submit
this.request({
onComplete: function(t) { alert(t.responseText) }
});
});

See http://prototypejs.org/api/form/request too :)

> I've tried the Event.observe(elm,...) call with prototype 1.6.0 and
> 1.5.1.1 Both have the same behavior and fail the same way.
> I would have tried the svn version too if I had rails installed at my
> work computer....

You don't need rails to have prototype trunk :)
svn checkout http://dev.rubyonrails.org/svn/rails/spinoffs/prototype/trunk
prototype

Best,
Nicolas

Thierry

unread,
Dec 18, 2007, 4:23:16 PM12/18/07
to Ruby on Rails: Spinoffs
> Please, while you're using Prototype, *use* Prototype :)
>
> var original = $(aryInp[cptInp]);
> var btn = new Element("input", { type: "button", className:
> original.className, rel: "ajax" }).setValue( $F(original) );
> btn.identify();
>
> original.replace(btn);
> btn.observe('click', elm.doCall);
>
> By using plain old DOM methods you will surely stumble into
> cross-browser issues, plus, wrting the code with Prototype will make
> it much more concise and easier to follow :)
>

I have to admit that for the 2 last years, my only use of prototype
was for the Ajax.Request and Array.each functions.
I never got paste those...
Maybe I should have, but as I ever did it my way, I feel a bit
uncomfortable to go back and re-learn another way.

Now, at work, we are using the X library, and I have to say that it
goes more on the way I'm used to work.
I really think that prototype is great, but at this stage, I feel more
in phase with the X library.
So, I think I'll stick to it.

>
>
> If you're only trying to intercept the submit of the form in order to
> do it via ajax, replacing the submit button is *not* the best way to
> do it, as people can still submit the form "normally" by hitting enter
> when focusing a form field. Instead, hijack the form's 'submit' event:
>
I thought of that, and I was doing it already, as the onSubmit event
would have called the ajax procedure too, and return false.
Thus, no form submit should have completed. But I didn't tested it.

> > I've tried the Event.observe(elm,...) call with prototype 1.6.0 and
> > 1.5.1.1 Both have the same behavior and fail the same way.
> > I would have tried the svn version too if I had rails installed at my
> > work computer....
>
> You don't need rails to have prototype trunk :)
> svn checkouthttp://dev.rubyonrails.org/svn/rails/spinoffs/prototype/trunk
> prototype

Hmm, I must have not looked enough.
I did checked out the trunk, but I had a series of separate js files,
and a rake file I had to use to compile the final prototype.js
As I was at work (and should not have messed with a personal project)
I didn't get further than that.

> Best,
> Nicolas

A really big Thank you for your time Nicholas.
And sorry for having wasted it.

Cheers.
Thierry.
Reply all
Reply to author
Forward
0 new messages