You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by la...@email.cz on 2014/02/19 16:16:33 UTC

Executing JS function from component ONCE

Hi everyone!



I've implemented component, which needs JavaScript function for proper 
positioning and I need to set this function as <body>'s "onload" and 
"onScroll" events. So, I have .js file with my possitioning function and 
also decorateBody() function which I need to call after page is created. 
Problem (or let say not-nice) is, that I can call it only (as far as I've 
tried) via 

javaScriptSupport.addScript("decorateBody();"); in @AfterRender method. It 
works, but when I use more of my components in one page, "decorateBody();" 
call is called x times, where x is number of components on the page.


I can also call the function as anonymous directly at js library, but then 
it goes to error as body tag does not exists in moment of library import.




Question 1: Is it possible to specify something "execute only once in page" 
on component level? (call from page containing the components is not 
solution for me, I want to have my component "independent")




Question 2: Is it possible to load js library AFTER page is created (body 
tag is rendered)? Everything what I've tried was loading js before body tag 
exists.




Thanks for any help in advance!

Best regards

Ladislav

Re: Executing JS function from component ONCE

Posted by Thiago H de Paula Figueiredo <th...@gmail.com>.
On Wed, 19 Feb 2014 12:16:33 -0300, <la...@email.cz> wrote:

> Hi everyone!

Hi!

> Question 1: Is it possible to specify something "execute only once in  
> page" on component level? (call from page containing the components is  
> not
> solution for me, I want to have my component "independent")

No.

> Question 2: Is it possible to load js library AFTER page is created (body
> tag is rendered)? Everything what I've tried was loading js before body  
> tag exists.

AFAIK, That's what happens already when you include or call JavaScript  
through JavaScriptSupport. Notice how Tapestry adds addScript()-added  
lines: their called only after the document ready JavaScript event is  
triggered. Even JavaScriptSupport- or @Import-included JavaScript files go  
to the bottom of the <body>.

-- 
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Executing JS function from component ONCE

Posted by la...@email.cz.
Hi!




I'm not sure if I used your proposal correctly, nevertheless "best" result 
was following (which leads me again to wrong workflow idea of non existing 
body element):

Uncaught TypeError: Cannot call method 'observe' of undefined





What is working for me is jQuery with 10 years old javaScript:




jQuery(document).ready(function() { 

 document.body.setAttribute("onload","setPosition();");

document.body.setAttribute("onScroll","setPosition();");

});





So, problem solved. Thanks for all answers!

Best regards

Ladislav


---------- Původní zpráva ----------
Od: Thiago H de Paula Figueiredo <th...@gmail.com>
Komu: Tapestry users <us...@tapestry.apache.org>
Datum: 20. 2. 2014 0:05:09
Předmět: Re: Executing JS function from component ONCE

"On Wed, 19 Feb 2014 18:48:02 -0300, <la...@email.cz> wrote:

> Hi!

Hi!

> var db = function decorateBody() {
> document.body.setAttribute("onload","setPosition();");
> document.body.setAttribute("onScroll","setPosition();");
> }

You're using JavaScript that looks like 10 years ago. Use event listeners 
for that. If you're using Prototype, it would be something like 
$$('body')[0].observe('load', setPosition); 
$$('body')[0].observe('scroll', setPosition); (this wasn't tested).

-- 
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org"

Re: Executing JS function from component ONCE

Posted by Thiago H de Paula Figueiredo <th...@gmail.com>.
On Wed, 19 Feb 2014 18:48:02 -0300, <la...@email.cz> wrote:

> Hi!

Hi!

> var db = function decorateBody() {
>     document.body.setAttribute("onload","setPosition();");
>      document.body.setAttribute("onScroll","setPosition();");
> }

You're using JavaScript that looks like 10 years ago. Use event listeners  
for that. If you're using Prototype, it would be something like  
$$('body')[0].observe('load', setPosition);  
$$('body')[0].observe('scroll', setPosition); (this wasn't tested).

-- 
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Executing JS function from component ONCE

Posted by Geoff Callender <ge...@gmail.com>.
Hi,

Let Tapestry do the initialisation for you. This may help:

	http://jumpstart.doublenegative.com.au/jumpstart/examples/javascript/robust

Cheers,
Geoff

On 20/02/2014, at 8:48 AM, <la...@email.cz> wrote:

> Hi!
> 
> Thanks for your hints, nevertheless I'm afraid problem is not solved... I'm 
> importing js file inside my component as you suggesting:
> @Import(stylesheet = "MyComponent.css", library="MyComponent.js")
> public class MyComponent {...}
> 
> Content of js is following:
> 
> function setPosition() {
>     // set of style changes
> }
> var db = function decorateBody() {
>     document.body.setAttribute("onload","setPosition();");
>      document.body.setAttribute("onScroll","setPosition();");
> }
> db(); 
> 
> 
> What I get in browser is:
> 
>   1. Uncaught TypeError: Cannot call method 'setAttribute' of null
> 
> 
> This leads me to thought that body element (I'm setting attributes on) is 
> not existing yet. Am I missing something? I've tried to check other 
> possibilities of javaScriptSupport, but nothing helped.
> Only working solution is to use addScript() as Dmitry suggested, I'm not 
> very happy with storing flag in request solution, but it is currently best 
> solution I have.
> 
> Best regards
> Ladislav
> 
> 
> 
> ---------- Původní zpráva ----------
> Od: Thiago H de Paula Figueiredo <th...@gmail.com>
> Komu: Tapestry users <us...@tapestry.apache.org>
> Datum: 19. 2. 2014 19:17:45
> Předmět: Re: Executing JS function from component ONCE
> 
> "On Wed, 19 Feb 2014 14:54:07 -0300, Dmitry Gusev <dm...@gmail.com> 
> wrote:
> 
>> Another option could be to store some attribute in the request scope and
>> only call javaScriptSupport.addScript once on the server side.
> 
> JavaScriptSupport.addSCript() is deprecated in T5.4. In addition, I've 
> just noticed, he's doing a wrong thing anyway: the call to decorateBody() 
> should be inside a .js file @Import'ed by the component. Tapestry only 
> includes each imported .js file once, so decorateBody() will be called 
> exactly once. Problem solved by doing the right thing. :)
> 
> -- 
> Thiago H. de Paula Figueiredo
> Tapestry, Java and Hibernate consultant and developer
> http://machina.com.br
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org"


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Executing JS function from component ONCE

Posted by la...@email.cz.
Hi!

Thanks for your hints, nevertheless I'm afraid problem is not solved... I'm 
importing js file inside my component as you suggesting:
@Import(stylesheet = "MyComponent.css", library="MyComponent.js")
public class MyComponent {...}

Content of js is following:

function setPosition() {
    // set of style changes
}
var db = function decorateBody() {
    document.body.setAttribute("onload","setPosition();");
     document.body.setAttribute("onScroll","setPosition();");
}
db(); 


What I get in browser is:

   1. Uncaught TypeError: Cannot call method 'setAttribute' of null
   

This leads me to thought that body element (I'm setting attributes on) is 
not existing yet. Am I missing something? I've tried to check other 
possibilities of javaScriptSupport, but nothing helped.
Only working solution is to use addScript() as Dmitry suggested, I'm not 
very happy with storing flag in request solution, but it is currently best 
solution I have.

Best regards
Ladislav



---------- Původní zpráva ----------
Od: Thiago H de Paula Figueiredo <th...@gmail.com>
Komu: Tapestry users <us...@tapestry.apache.org>
Datum: 19. 2. 2014 19:17:45
Předmět: Re: Executing JS function from component ONCE

"On Wed, 19 Feb 2014 14:54:07 -0300, Dmitry Gusev <dm...@gmail.com> 
wrote:

> Another option could be to store some attribute in the request scope and
> only call javaScriptSupport.addScript once on the server side.

JavaScriptSupport.addSCript() is deprecated in T5.4. In addition, I've 
just noticed, he's doing a wrong thing anyway: the call to decorateBody() 
should be inside a .js file @Import'ed by the component. Tapestry only 
includes each imported .js file once, so decorateBody() will be called 
exactly once. Problem solved by doing the right thing. :)

-- 
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org"

Re: Executing JS function from component ONCE

Posted by Thiago H de Paula Figueiredo <th...@gmail.com>.
On Wed, 19 Feb 2014 14:54:07 -0300, Dmitry Gusev <dm...@gmail.com>  
wrote:

> Another option could be to store some attribute in the request scope and
> only call javaScriptSupport.addScript once on the server side.

JavaScriptSupport.addSCript() is deprecated in T5.4. In addition, I've  
just noticed, he's doing a wrong thing anyway: the call to decorateBody()  
should be inside a .js file @Import'ed by the component. Tapestry only  
includes each imported .js file once, so decorateBody() will be called  
exactly once. Problem solved by doing the right thing. :)

-- 
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Executing JS function from component ONCE

Posted by Dmitry Gusev <dm...@gmail.com>.
Another option could be to store some attribute in the request scope and
only call javaScriptSupport.addScript once on the server side.


On Wed, Feb 19, 2014 at 8:19 PM, Thiago H de Paula Figueiredo <
thiagohp@gmail.com> wrote:

> On Wed, 19 Feb 2014 12:16:33 -0300, <la...@email.cz> wrote:
>
>  javaScriptSupport.addScript("decorateBody();"); in @AfterRender method.
>> It works, but when I use more of my components in one page,
>> "decorateBody();"
>> call is called x times, where x is number of components on the page.
>>
>
> That's very easy and Tapestry-agnostic to do: just have your function to
> set some variable or add an attribute to a DOM element to mark that it was
> already called once. When running, check whether it was already called. If
> not, run as normal. Otherwise, just don't do anything.
>
>
> --
> Thiago H. de Paula Figueiredo
> Tapestry, Java and Hibernate consultant and developer
> http://machina.com.br
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>


-- 
Dmitry Gusev

AnjLab Team
http://anjlab.com

Re: Executing JS function from component ONCE

Posted by Thiago H de Paula Figueiredo <th...@gmail.com>.
On Wed, 19 Feb 2014 12:16:33 -0300, <la...@email.cz> wrote:

> javaScriptSupport.addScript("decorateBody();"); in @AfterRender method.  
> It works, but when I use more of my components in one page,  
> "decorateBody();"
> call is called x times, where x is number of components on the page.

That's very easy and Tapestry-agnostic to do: just have your function to  
set some variable or add an attribute to a DOM element to mark that it was  
already called once. When running, check whether it was already called. If  
not, run as normal. Otherwise, just don't do anything.

-- 
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org