3

i have problem to use widgetVar while its name is generated dynamicly. How properly we can call such widget ? Code of component:

<cc:attribute name="id" required="true" type="java.lang.String" />
...
<cc:implementation>
    <p:selectOneRadio widgetVar="widgetVariable#{cc.attrs.id}" id="#{cc.attrs.id}" required="false" immediate="#{cc.attrs.immediate}"
                      value="#{cc.attrs.value}">
        <p:ajax event="click" oncomplete="checkRadio()"/>
        <cc:insertChildren/>
    </p:selectOneRadio>

    <script type="text/javascript">
        /*  <![CDATA[ */

        function checkRadio() {
            var widgetVariable = widgetVariable#{cc.attrs.id}; //HERE PROBLEM
            widgetVariable.dosmth();
        }

        /*    ]]> */
    </script>
</cc:implementation>  

thats what is wird that it works, but when i uses many istance of this component on page widgetwar sometimes get crazy and make javascript for many istance of component.

Edit: everything works fine. Anyway i have one new problem. I created in this .js file some global state variable.

var state = -1;

function checkRadio() {
        var widgetVariable = widgetVariable#{cc.attrs.id}; //HERE PROBLEM
        widgetVariable.dosmth(state);
}

But each state should be only for one composite istance, atm every composite use this var, some ideas?

user2771738
  • 913
  • 11
  • 31

1 Answers1

2

There are actually 2 problems.

The first problem is that you're declaring JS functions in a XHTML file instead of a real JS file. If you've multiple of those components, then you're basically generating multiple JS functions checkRadio() to the HTML output. Pull the page in your browser, rightclick and View Source. You'll basically see

<script type="text/javascript">
    function checkRadio() {
        // ...
    }
</script>
<script type="text/javascript">
    function checkRadio() {
        // ...
    }
</script>
<script type="text/javascript">
    function checkRadio() {
        // ...
    }
</script>
...

They're overriding each other until the last one. So when checkRadio() is called, actually the last one will be invoked. This obviously isn't right.

You should have only one function. You can externalize the variable by simply making it a function argument. Even more, you should not be writing JS code in a XHTML file, but in a standalone JS file which you include by <h:outputScript>. Additional bonus, it will automatically make sure that there's only one JS file loaded even though you've multiple composite components.

<cc:implementation>
    <h:outputScript name="myComposite.js" />
    ...
    <p:ajax event="click" oncomplete="checkRadio('#{cc.attrs.id}')" />
</cc:implementation>

Coming back to your concrete question, your second problem, you can make use of window[variableName] notation to get a hand of a global (window) variable by a dynamically composed variable name. So, the checkRadio() function in your myComposite.js (name it whatever you want, but the same filename as myComposite.xhtml would be most self-documenting) should look like this:

function checkRadio(compositeId) {
   var widgetVariableName = "widgetVariable" + compositeId;
   var widgetVariable = window[widgetVariableName];
   widgetVariable.dosmth();
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • where should i put this js file? i added libary tag I puted it into place where composite component is, but it show me some erorr in page source when i am going to page with this composite component: ... ... – user2771738 Jan 17 '14 at 11:43
  • 1
    The same place as all other JSF resources. In the `/resources` folder. If you want it to be in the same folder as composite XHTML, just alter `` accordingly based on the actual `/resources`-relative path. By the way, "js" is absolutely a bad library name. See also among others http://stackoverflow.com/questions/11988415/what-is-the-jsf-resource-library-for-and-how-should-it-be-used – BalusC Jan 17 '14 at 11:47
  • Just pass it as another function argument? – BalusC Jan 17 '14 at 12:25
  • each Composite component can have many states, and i need to remember this states. for example i got 1th state = 3 2nd state = 2 3rd state = 0 atm this var state is global and all of them uses it. So passing its not a solution while this var can have 1 state at once – user2771738 Jan 17 '14 at 12:30
  • I'm not seeing how passing it as another function argument forms a problem. – BalusC Jan 17 '14 at 12:35
  • I think we talk about 2 diffrent things. I have problem to crate dynamicly variables for states of each component, cus i have only one state variable and even that var state is in own file it still included in javascript of all components at page. – user2771738 Jan 17 '14 at 12:39
  • ok i fixed it. I didnt knew that I even dont need to declare global JS variables so i replaced each state to: window[stateName] where stateName = "state" + compositeId; //compositeID from function arguments – user2771738 Jan 17 '14 at 12:48