a4j: jsFunction с actionListener внутри h: dataTable

У меня проблема с использованием a4j:jsFunction с actionListener внутри h:dataTable, когда я хочу вызвать действие над определенной строкой с помощью a4j:commandLink, оно работает безупречно, но когда я хочу вызвать действие с помощью a4j:jsFunction & actionListener, это всегда вызывается для последнего элемента в dataTable Позвольте мне привести пример:

    <a4j:form ajaxSubmit="true" reRender="mainForm" id="mainForm">
        <a4j:region>
            <t:saveState value="#{ts.list}" />
        </a4j:region>

        <h:dataTable value="#{ts.list}" var="el" binding="#{ts.bind}">
        <h:column>#{el}</h:column>>
        <h:column>
            <a4j:commandLink actionListener="#{ts.rem}">
                    <h:outputText value="delete by CMDLink" />
                </a4j:commandLink>
            </h:column>
        <h:column>
                <a href="#" onclick="okClicked();">delete by okClicked</a>
                <a4j:jsFunction name="okClicked"
                    actionListener="#{ts.rem}"
                />
        </h:column>
   </h:dataTable>
    </a4j:form>

теперь код компонента:

package com.sth;

import java.util.ArrayList;
import java.util.List;

import javax.faces.component.UIData;
import javax.faces.event.ActionEvent;

public class Ts {

    private List<String> list = new ArrayList<String>();
    private UIData bind;

    public Ts(){
        list.add("element1");
        list.add("element2");
        list.add("element3");
        list.add("element4");
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void rem(ActionEvent ae) {
        String toRem = (String) bind.getRowData();
        System.out.println("Deleting " + toRem);
        list.remove(toRem);
    }

    public UIData getBind() {
        return bind;
    }

    public void setBind(UIData bind) {
        this.bind = bind;
    }

}

когда я использую a4j:commandLink для удаления элемента, он работает так, как ожидалось, но когда я использую a4j:jsFunction для вызова actionListener, он вызывает действие против последнего элемента :( Есть идеи?


person JQueryNeeded    schedule 18.03.2010    source источник
comment
В чем причина предпочитать a4j:jsFunction выше a4j:commandLink в любом случае?   -  person BalusC    schedule 18.03.2010
comment
Я хочу сделать модальное окно подтверждения с помощью jQuery, чтобы диалоговое окно jQuery запускало okClicked() из jsFunction   -  person JQueryNeeded    schedule 18.03.2010


Ответы (3)


вы можете достичь своей цели, переместив ‹a4j:jsFunction> из элемента управления ‹h:datatable>

это пример

 <a4j:form ajaxSubmit="true" reRender="mainForm" id="mainForm">

    <h:dataTable value="#{ts.list}" var="el" binding="#{ts.bind}">
      <h:column>#{el}</h:column>>
      <h:column>
            <a4j:commandButton 
                onclick="#{rich:component
                     ('confirmation')}.show();return false">Delete</a4j:commandButton>
      </h:column>
    </h:dataTable>
    <a4j:jsFunction name="remove" action="#{ts.remove(el)}" reRender="mainForm"/>
 </a4j:form>

Диалог подтверждения:

<rich:modalPanel id="confirmation" width="250" height="150">
        <f:facet name="header">
            <h:panelGrid columns="2">
                <h:graphicImage value="/img/delete.gif"/>
                <h:outputText value="Confirmation"/>
            </h:panelGrid>
        </f:facet>
        <h:panelGrid style="height: 100%">
            <h:panelGrid columns="2" cellpadding="5px">
                <h:graphicImage value="/img/error_large.gif"/>
                <h:outputText value="Delete ?" style="font-size: large;"/>
            </h:panelGrid>
            <h:panelGroup style="margin-top: 20px">
                <input type="button" value="Yes" style="width: 100px"
                       onclick="#{rich:component('confirmation')}.hide();remove();return false"/>
                <input type="button" value="No" style="width: 100px"
                       onclick="#{rich:component('confirmation')}.hide();return false"/>
            </h:panelGroup>
        </h:panelGrid>
    </rich:modalPanel>
person Valeriy    schedule 09.10.2010

Судя по комментариям, вы просто хотите запустить диалог подтверждения. Вы также можете использовать для этого a4j:commandLink, вызвать его в атрибуте onclick и позволить ему вернуть либо true, либо false, чтобы разрешить или заблокировать действие. Вот пример запуска, который вы бы сделали со стандартным диалоговым окном подтверждения:

<a4j:commandLink onclick="return confirm('Are you sure?');">

Таким образом, вам не нужно часами бороться/отлаживать странное поведение a4j:jsFunction.

person BalusC    schedule 18.03.2010
comment
Спасибо, BalusC, за ответ :-) Я уже использовал это решение, я хотел задействовать диалоговое окно jQuery, чтобы оно было «дружественным для глаз», но, похоже, для этого нет простого решения. - person JQueryNeeded; 18.03.2010
comment
Да, я знаю. Это был просто стартовый пример. Замените confirm() вашей функцией jQuery. Весь смысл в том, чтобы позволить ему возвращать либо true, либо false, чтобы заблокировать действие ссылки по умолчанию. - person BalusC; 18.03.2010
comment
к сожалению, диалоговое окно jQuery не работает таким образом, несколько недель назад я боролся с той же проблемой: stackoverflow.com/questions/1812500/ - person JQueryNeeded; 18.03.2010

Насколько я понимаю, с тегом a4j:jsFunction:

<a4j:jsFunction name="okClicked" actionListener="#{ts.rem}" />

будучи помещенным в столбец таблицы данных, функция JavaScript с именем okClicked будет добавлена ​​на HTML-страницу в столбце для каждой строки таблицы. Имея одно и то же имя, каждая функция JavaScript перезаписывает определение предыдущей, так что при вызове okClicked() фактически выполняется только последняя определенная функция. Вот почему вызывается actionListener, который вызывает «действие против последнего элемента».

Обойти это можно было бы, включив индекс строки как часть имени функции JavaScript, создаваемой тегом a4j:jsFunction:

<h:dataTable value="#{ts.list}" var="el" binding="#{ts.bind}" rowIndexVar="index">
    <h:column>
        <a href="#" onclick="okClicked#{index}();">delete by okClicked</a>
        <a4j:jsFunction name="okClicked#{index}" actionListener="#{ts.rem}"/>
    </h:column>
</h:datatable>

Я не тестировал вышеуказанное решение (и я не знаю, возникнет ли проблема с привязкой #{ts.rem} к функции JS actionListener вместо привязки ее к commandLink actionListener), но если значение onClick okClicked#{index}(); не работает напрямую, затем вместо этого вызовите функцию javaScript, которая создает имя функции из строки, построенной из значения индекса:

function onClicked(row) {
    functionStr = "okClicked" + row;
    window[functionStr]();
}

Мне пришлось использовать что-то подобное, требующее сетки «jsFunction» в таблице данных, где у меня было несколько столбцов для обработки, а также несколько строк.

Надеюсь, это будет полезно для других в будущем.

person Martin    schedule 17.09.2012