Параметр, переданный от дочернего элемента p:timeline, имеет значение null в методе действия.

Моя цель: мне нравится добавлять команду commandLink в качестве дочерней для PrimeFaces. p:timeline Пользователь должен иметь возможность щелкнуть одну из этих ссылок. Щелчок должен вызвать метод в моем компоненте (CDI, ViewScoped). В методе действия мне нужна информация из выбранного элемента на временной шкале. В зависимости от результата метода действия может быть переход к другому пользовательскому интерфейсу.

Моя попытка: полная форма довольно короткая и простая. Так что лучше опубликую целиком:

<h:form>
  <p:fieldset legend="Upcoming Gates">
    <p:timeline height="200px" style="width: 99%;"
           start="#{facilitatorCockpit.timelineStart}"
           end="#{facilitatorCockpit.timelineEnd}"
           value="#{facilitatorCockpit.timelineModel}"
           var="timelineitem"
           selectable="false"
           zoomable="false"
           moveable="false"                                
           >     
       <h:outputText value="#{timelineitem.systemElement}"/> <br/>
       <p:commandLink action="#{facilitatorCockpit.openStatusSheet(timelineitem.roadmapId)}"
                               process="@this"  value="#{timelineitem.roadmapId}"
                               title="Open Status Sheet"/>         
    </p:timeline>
  </p:fieldset>
</h:form>

Текущее поведение: Как видно из xhtml, я показываю некоторый "Id" на элементе временной шкалы. Этот идентификатор правильно отображается в пользовательском интерфейсе. Метод действия выполняется, но переданный параметр разрешается в null на стороне сервера.

Я использую ту же самую попытку из таблицы данных (тот же пользовательский интерфейс, просто другая форма), где она работает нормально. Я просто не могу вызвать метод действия с такими параметрами изнутри p:timeline

На моей странице нет вложенных форм, в консоли браузера не отображаются ошибки JavaScript. Я также пробовал все комбинации commandLink/button и action/listener, несмотря на то, что тот, что используется в примере, именно то, что мне нужно, но с теми же результатами.

Я использую PF 6.0 и Mojarra 2.2.10.

Обновление: я заметил небольшую разницу в сгенерированном HTML и сгенерированном HTML, когда я использую этот тип commandLink, например. в табличном виде.

В p:timeline один и тот же идентификатор и вызовы JavaScript генерируются для каждого элемента временной шкалы:

<a id="j_idt88:j_idt94" href="#" class="ui-commandlink ui-widget" 
   aria-label="Open Status Sheet" 
   onclick="PrimeFaces.ab({s:&quot;j_idt88:j_idt94&quot;,p:&quot;j_idt88:j_idt94&quot;});
            return false;" 
   title="Open Status Sheet">FPR 137
</a>
<!-- .... -->
<a id="j_idt88:j_idt94" href="#" class="ui-commandlink ui-widget"
    aria-label="Open Status Sheet" 
    onclick="PrimeFaces.ab({s:&quot;j_idt88:j_idt94&quot;,p:&quot;j_idt88:j_idt94&quot;});
           return false;"
    title="Open Status Sheet">FPR 138

Current Solution: Based on the accepted answer my current approach now looks like this:

<p:commandLink action="#{facilitatorCockpit.openStatusSheetFromTimeline()}"
    process="@this"
    value="#{timelineitem.phase.label}"
    title="Open Status Sheet"
>         
   <f:param name="id" value="#{timelineitem.roadmapId}" />
</p:commandLink>

Я добавил дополнительный метод действия в вспомогательный компонент, который делегирует исходный.

public String openStatusSheetFromTimeline() {
    Map<String, String> params = FacesContext.getCurrentInstance()
        .getExternalContext()
        .getRequestParameterMap();
    String roadmapId = params.get("id");
    Long id = Long.parseLong(roadmapId);
    return openStatusSheet(id);
}

Тем не менее мне просто интересно, что не так с первоначальным подходом.


person stg    schedule 14.01.2017    source источник


Ответы (2)


Почему бы вам не использовать

<p:ajax event="select" listener="#{facilitatorCockpit.onSelect}"/> ?

В метод onSelect вы можете вызвать openStatusSheet или реорганизовать openStatusSheet для TimelineSelectEvent. Идентификатор можно сохранить в атрибуте данных.

public void onSelect(TimelineSelectEvent e) {  
    TimelineEvent timelineEvent = e.getTimelineEvent();  

    // get your Id
    String roadmapId = timelineEvent.getDate.toString();
} 

Изменить: второе решение

Для отправки идентификатора с пользовательскими компонентами используйте p:commandButton с f:param.

    <p:timeline id="timeline" value="#{timelineBean.model}"
        height="250px" selectable="true" var="item">

        <p:commandButton value="Click #{item}"
            actionListener="#{timelineBean.click()}">
            <f:param name="id" value="#{item}" />
        </p:commandButton>
    </p:timeline>

И в свой фоновый компонент вы можете поймать параметр, например

public void click() {
    Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
    String roadmapId = params.get("id");

    ...
}

Таким образом, вы можете вставить 2 или более командных кнопок.

person jklee    schedule 15.01.2017
comment
tyvm за ответ. Возможно, это компромисс для текущей ситуации. Тем не менее, есть несколько проблем с ним. Суть в том, что я ожидаю изменения пользовательского интерфейса, когда к одному событию на временной шкале будет добавлено более одной командной ссылки. когда я использую событие выбора временной шкалы, я потеряю эту опцию. - person stg; 15.01.2017
comment
Вот так. Я добавил второе решение для этого варианта использования. - person jklee; 16.01.2017
comment
Передача параметра с помощью f:param сделала свое дело! Однако до сих пор не знаю, почему это не работает с первоначальным подходом в моем вопросе. - person stg; 16.01.2017

это означает, что ваш timelineitem.roadmapId равен null , а также сделайте свой управляемый bean-компонент ViewScope или Session Scope. распечатать параметр перед проходом.

person Armen Arzumanyan    schedule 14.01.2017
comment
Компонент имеет ViewScoped. В пользовательском интерфейсе правильный идентификатор отображается в виде метки на элементе временной шкалы. - person stg; 15.01.2017