Search code examples
formsjsfjsf-2primefacesdatalist

Multiple remoteCommands in a dataList, but only one call


This one is tricky and I do not understand why it works like this:

<p:dataList var="item" value="#{recb.friends}" type="definition">
    <p:column>
        <h:form>
            <p:remoteCommand name="getTaste" process="@this" 
                         actionListener="#{item.calculateTaste( recb.username )}"
                         autoRun="true" oncomplete="poll.start()" />    
            <p:poll autoStart="false" update="@form" interval="1"
                widgetVar="poll" oncomplete="poll.stop()" />                    
        </h:form>
    </p:column>
</p:dataList>

So what I expect to happen is: for each ITEM it will call the calculateTaste method. What happens is: there is only one call, just for the last item in the dataList.

I run out of ideas what is wrong. I added columns so the ID's are generated, still it's not working :(.


Solution

  • As to the cause of the problem, this construct generates multiple JS variables with exactly the same name getTaste in the same scope, basically like so:

    <script>var getTaste = function() { ... }</script>
    <script>var getTaste = function() { ... }</script>
    <script>var getTaste = function() { ... }</script>
    ...
    

    They're basically overriding each other in the order they're declared and when invoking getTaste() on DOM ready basically the last one would be actually invoked. This matches exactly the symtoms you're observing (looking in the generated HTML source yourself by rightclick, View Source in browser would also have told you that).

    You'd like to give them each an unique JS variable name. You can make use of the varStatus attribute of the <p:dataList> to get the current iteration status with among others the getIndex() method.

    <p:dataList ... varStatus="loop">
        ...
        <p:remoteCommand name="getTaste#{loop.index}" ... /> 
    

    This way the generated code ends up with unique JS variable names:

    <script>var getTaste0 = function() { ... }</script>
    <script>var getTaste1 = function() { ... }</script>
    <script>var getTaste2 = function() { ... }</script>
    ...
    

    I'd also apply the same solution on <p:poll widgetVar> by the way.

    <p:dataList ... varStatus="loop">
        ...
        <p:remoteCommand name="getTaste#{loop.index}" ...
            oncomplete="poll#{loop.index}.start()" /> 
        <p:poll ...
            widgetVar="poll#{loop.index}" oncomplete="poll#{loop.index}.stop()" />