JSF:更改 jstl c:foreach 数组中的组件样式不起作用

发布于 2024-09-16 10:50:15 字数 2802 浏览 3 评论 0原文

此代码显示索引并使用 RichFaces 的 标记执行操作。从技术上来说它工作得很好。只有先前选择的字母的样式没有被重置(尽管执行了适当的代码部分)。有谁知道问题出在哪里以及如何解决?

JSF 页面:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:c="http://java.sun.com/jstl/core" xmlns:rich="http://richfaces.org/rich" xmlns:a4j="http://richfaces.org/a4j">
 <head>
  <style>
   a.selected {
    text-decoration: underline;
   }

   a.unselected {
    text-decoration: none;
   }
  </style>
 </head>
    <body>
  <rich:panel id="result">
     hello
      <h:form id="myForm"> 
       <c:forEach var="letter" items="#{testBean.letters}" >
      <a4j:commandLink id="${letter}" value="${letter}" actionListener="#{testBean.startWith}" reRender="result" styleClass="unselected"/>&#160;
           </c:forEach>
   </h:form>
  </rich:panel>
  <a4j:keepAlive beanName="testBean" />
    </body>
</html>

请注意,它使用 来使支持 bean 在 Ajax 请求之间保持活动状态。

支持 bean(请求范围):

public class testBean
{
 private String startLetter = null; // selects from alphabetical page
 private String[] letters = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
 private UIComponent currentStartWithLetter;

 public void startWith(ActionEvent actionEvent)
 {
  FacesContext facesContext = FacesContext.getCurrentInstance();
  ELContext elContext = facesContext.getELContext();
  Application app = facesContext.getApplication();
  ExpressionFactory elFactory = app.getExpressionFactory();
  ValueExpression valueExp;
  if (currentStartWithLetter != null) {
   valueExp = elFactory.createValueExpression(elContext, "unselected",Object.class);
   currentStartWithLetter.setValueExpression("styleClass", valueExp);
  } 
  currentStartWithLetter = actionEvent.getComponent();
  startLetter = currentStartWithLetter.getId();
  valueExp = elFactory.createValueExpression(elContext, "selected",Object.class);
  currentStartWithLetter.setValueExpression("styleClass", valueExp);
  someAction(actionEvent);    
 }


 public void setLetters(String[] letters) {
  /* nothing to do */
 }

 public String[] getLetters() {
  return letters;
 }

 public String getStartLetter() {
  return startLetter;
 }

 public void setStartLetter(String startLetter) {
  this.startLetter = startLetter;

 }
}

This code displays an index and performs an action using RichFaces' <a4j:commandLink> tag. It works technically fine. Only the style of previously selected letter is not been reset (altough the appropriate code part is executed). Does anybody know where the problem is and how to solve it?

The JSF page:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:c="http://java.sun.com/jstl/core" xmlns:rich="http://richfaces.org/rich" xmlns:a4j="http://richfaces.org/a4j">
 <head>
  <style>
   a.selected {
    text-decoration: underline;
   }

   a.unselected {
    text-decoration: none;
   }
  </style>
 </head>
    <body>
  <rich:panel id="result">
     hello
      <h:form id="myForm"> 
       <c:forEach var="letter" items="#{testBean.letters}" >
      <a4j:commandLink id="${letter}" value="${letter}" actionListener="#{testBean.startWith}" reRender="result" styleClass="unselected"/> 
           </c:forEach>
   </h:form>
  </rich:panel>
  <a4j:keepAlive beanName="testBean" />
    </body>
</html>

Note that it is using <a4j:keepalive> to keep the backing bean alive between Ajax requests.

The backing bean (request scoped):

public class testBean
{
 private String startLetter = null; // selects from alphabetical page
 private String[] letters = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
 private UIComponent currentStartWithLetter;

 public void startWith(ActionEvent actionEvent)
 {
  FacesContext facesContext = FacesContext.getCurrentInstance();
  ELContext elContext = facesContext.getELContext();
  Application app = facesContext.getApplication();
  ExpressionFactory elFactory = app.getExpressionFactory();
  ValueExpression valueExp;
  if (currentStartWithLetter != null) {
   valueExp = elFactory.createValueExpression(elContext, "unselected",Object.class);
   currentStartWithLetter.setValueExpression("styleClass", valueExp);
  } 
  currentStartWithLetter = actionEvent.getComponent();
  startLetter = currentStartWithLetter.getId();
  valueExp = elFactory.createValueExpression(elContext, "selected",Object.class);
  currentStartWithLetter.setValueExpression("styleClass", valueExp);
  someAction(actionEvent);    
 }


 public void setLetters(String[] letters) {
  /* nothing to do */
 }

 public String[] getLetters() {
  return letters;
 }

 public String getStartLetter() {
  return startLetter;
 }

 public void setStartLetter(String startLetter) {
  this.startLetter = startLetter;

 }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦途 2024-09-23 10:50:15

我总觉得如果我在代码中引用 UIComponent 我正在做一些困难的事情。我就是这样做的。

尝试使用 代替 actionListener。另外,避免重新渲染整个表单,它会在某些浏览器中导致问题:

<h:panelGroup id="results">
  <a4j:repeat var="letterBean" items="#{testBean.letters}" >
    <a4j:commandLink id="letter" value="#{letterBean.letter}" reRender="results" styleClass="#{letterBean.selected ? 'selected' : 'unselected'}">
      <f:setPropertyActionListener value="#{letterBean}" target="#{testBean.selected}"/>
    </a4j:commandLink> 
  </a4j:repeat>
</h:panelGroup>

新 bean 类:

public class LetterBean {
  private final String letter;
  private boolean selected;

  public LetterBean (String letter) {
    this.letter = letter;
  }

  //getters and setters

}

startWith 替换为:

public void setSelected(LetterBean selectedBean) {
  for (LetterBean letter : letterBeans) {
    letter.setSelected(false);
  }
  selectedBean.setSelected(true);
}

I always feel that if I'm referencing UIComponent in my code I'm doing something the hard way. Here's how I'd do this.

Try using <f:setPropertyActionListener> and <a4j:repeat> in place of actionListener and <c:forEach>. Also, avoid rerendering whole forms, it causes issues in some browsers:

<h:panelGroup id="results">
  <a4j:repeat var="letterBean" items="#{testBean.letters}" >
    <a4j:commandLink id="letter" value="#{letterBean.letter}" reRender="results" styleClass="#{letterBean.selected ? 'selected' : 'unselected'}">
      <f:setPropertyActionListener value="#{letterBean}" target="#{testBean.selected}"/>
    </a4j:commandLink> 
  </a4j:repeat>
</h:panelGroup>

New bean class:

public class LetterBean {
  private final String letter;
  private boolean selected;

  public LetterBean (String letter) {
    this.letter = letter;
  }

  //getters and setters

}

replace startWith with:

public void setSelected(LetterBean selectedBean) {
  for (LetterBean letter : letterBeans) {
    letter.setSelected(false);
  }
  selectedBean.setSelected(true);
}
倥絔 2024-09-23 10:50:15

我修改了代码,将 :

if (currentStartWithLetter != null) {
 valueExp = elFactory.createValueExpression(elContext, "unselected",Object.class);
 currentStartWithLetter.setValueExpression("styleClass", valueExp);
} 

更改为

if (currentStartWithLetter != null) {
 valueExp = elFactory.createValueExpression(elContext, "unselected",Object.class);
 currentStartWithLetter = (UIComponent) actionEvent.getComponent().findComponent(startLetter);
 currentStartWithLetter.setValueExpression("styleClass", valueExp);
} 

并且它有效。

问题似乎是 currentStartWithLetter 不再引用相同的组件,因为调用之间的 actionEvent 不同。

I modified the code changing :

if (currentStartWithLetter != null) {
 valueExp = elFactory.createValueExpression(elContext, "unselected",Object.class);
 currentStartWithLetter.setValueExpression("styleClass", valueExp);
} 

into

if (currentStartWithLetter != null) {
 valueExp = elFactory.createValueExpression(elContext, "unselected",Object.class);
 currentStartWithLetter = (UIComponent) actionEvent.getComponent().findComponent(startLetter);
 currentStartWithLetter.setValueExpression("styleClass", valueExp);
} 

and it works.

The problem seems to be that currentStartWithLetter does not refer to the same component anymore because the actionEvent is different between calls.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文