简体   繁体   English

复合组件mojarra与myfaces内部的ajax(使用jquery)

[英]ajax inside composite component mojarra vs myfaces (using jquery)

Short summary: 简短的摘要:

The project: a composite component that lets me filter a list and update an outer component 项目:一个复合组件,可让我过滤列表并更新外部组件

The problem: myfaces 2.1.10 works, mojarra 2.2.1 does not work, but I want to use jsf 2.2 问题:myfaces 2.1.10有效,mojarra 2.2.1不起作用,但我想使用jsf 2.2

The composite component filteredList.xhtml 复合组件filteredList.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:composite="http://java.sun.com/jsf/composite" xmlns:ui="http://java.sun.com/jsf/facelets">
  <composite:interface>
    <composite:attribute name="label" required="false" default="filter" type="java.lang.String" />
    <composite:attribute name="filter" required="true" type="java.lang.String" />
    <composite:attribute name="list" required="true" type="java.util.List" />
    <composite:attribute name="valueMask" required="false" type="" />
    <composite:attribute name="outputId" required="false" type="java.lang.String" />
    <composite:attribute name="height" required="false" default="128" type="java.lang.Integer" />
    <composite:attribute name="width" required="false" default="128" type="java.lang.Integer" />
    <composite:attribute name="destinationId" required="false" type="java.lang.String" />
    <composite:attribute name="rowClasses" required="false" type="java.lang.String" />
    <composite:attribute name="hoverClass" required="false" default="" type="java.lang.String" />
    <composite:attribute name="innerCellClasses" required="false" default="" type="java.lang.String" />
    <composite:attribute name="repeatClassOdd" required="false" default="" type="java.lang.String" />
    <composite:attribute name="repeatClassEven" required="false" default="" type="java.lang.String" />
  </composite:interface>
  <composite:implementation>
    <h:outputStylesheet name="css/elements.css" />
    <h:panelGrid columns="2">
      <h:outputText value="#{composite.attrs.label}" />
      <h:inputText id="filterfield" value="#{composite.attrs.filter}">
        <f:ajax event="keyup" render="table" />
      </h:inputText>
    </h:panelGrid>
    <div id="box#{cc.clientId}" style="overflow: auto">
      <h:dataTable id="table" value="#{composite.attrs.list}" var="elem" rowClasses="#{composite.attrs.rowClasses}">
        <h:column>
          <div id="choose#{elem.id}" style="cursor: pointer" class="#{composite.attrs.hoverClass}">
            <h:outputText value="#{elem.html}" rendered="#{elem.renderHtml}" />
            <h:dataTable value="#{elem.list}" var="l" rendered="#{elem.renderDatatable}" rowClasses="#{composite.attrs.innerCellClasses}">
              <h:column>
                <h:outputText value="#{l}" />
              </h:column>
            </h:dataTable>
            <ui:repeat value="#{elem.list}" var="l" varStatus="index" rendered="#{elem.renderRepeat}" columnClasses="#{composite.attrs.innerCellClasses}">
              <div class="#{index.odd ? composite.attrs.repeatClassOdd : composite.attrs.repeatClassEven}" style="display: inline">
                <h:outputText value="#{l}" />
              </div>
            </ui:repeat>
          </div>
          <ui:fragment rendered="#{composite.attrs.destinationId != null}">
            <script type="text/javascript">
              $(document).ready(function(){
                $("[id='choose#{elem.id}']").click(function(){
                  $("[id='#{composite.attrs.destinationId}']").val("#{elem.id}");
                  <ui:fragment rendered="#{cc.attrs.valueMask != null}">
                    $("[id='#{composite.attrs.outputId}']").text("#{composite.attrs.valueMask.getMask(elem.id)}");
                  </ui:fragment>
                  $("[id='#{composite.attrs.destinationId}']").trigger('change');
                });
              });
            </script>
          </ui:fragment>
        </h:column>
      </h:dataTable>
    </div>
    <script type="text/javascript">
      $(document).ready(function(){
        $("[id='box#{composite.clientId}']").height(#{composite.attrs.height}).width(#{composite.attrs.width});
      });
    </script>
  </composite:implementation>
</ui:composition>

Usage of this component: 该组件的用法:

<mycomponent:filteredList valueMask="#{testAction.valueMask}" label="label.filter" list="#{testAction.listFilter.list}" filter="#{testAction.listFilter.filter}" height="128" width="384" rowClasses="odd,even" hoverClass="hoverClass" inputfieldClasses="stayontop,stayontop" repeatClassOdd="oddy"
        repeatClassEven="eveny" />

Used class TestFilter: 使用的类TestFilter:

public class TestFilter implements FilterInterface
{
  private String filter;

  @Override
  public List<ListFilterElem> doFilter(List<ListFilterElem> unfilteredList)
  {
    if (filter == null || filter.trim().equals(""))
    {
      return unfilteredList;
    }
    else
    {
      String[] s = filter.split("\\s+");
      Set<ListFilterElem> filtered = new LinkedHashSet<ListFilterElem>();
      for (String f : s)
      {
        for (ListFilterElem e : unfilteredList)
        {
          if (e.containsIgnoreCase(f))
          {
            filtered.add(e);
          }
        }
      }
      return new ArrayList<ListFilterElem>(filtered);
    }
  }

  @Override
  public String getFilter()
  {
    return filter;
  }

  @Override
  public void setFilter(String filter)
  {
    this.filter = filter;
  }
}

Used class TestListFilterElem: 使用的类TestListFilterElem:

public class TestListFilterElem implements ListFilterElem
{
  private Integer id;
  private List<String> subList;

  public TestListFilterElem(Integer id, List<String> subList)
  {
    this.id = id;
    this.subList = subList;
  }

  @Override
  public String getHtml()
  {
    StringBuilder buf = new StringBuilder();
    for (String s : subList)
    {
      buf.append(s);
      buf.append(" ");
    }
    return buf.toString();
  }

  @Override
  public Integer getId()
  {
    return id;
  }

  @Override
  public Boolean containsIgnoreCase(String needle)
  {
    return getHtml().toLowerCase().contains(needle.toLowerCase());
  }

  @Override
  public List<String> getList()
  {
    return subList;
  }

  @Override
  public Boolean getRenderDatatable()
  {
    return false;
  }

  @Override
  public Boolean getRenderHtml()
  {
    return false;
  }

  @Override
  public Boolean getRenderRepeat()
  {
    return true;
  }
}

Used class ListFilter: 使用的类ListFilter:

public class ListFilter
{
  private List<ListFilterElem> list;
  private FilterInterface filterInterface;

  public ListFilter(FilterInterface filterInterface)
  {
    this.filterInterface = filterInterface;
    list = new ArrayList<ListFilterElem>();
  }

  public void addListElem(ListFilterElem elem)
  {
    list.add(elem);
  }

  public void addListElems(List<ListFilterElem> elems)
  {
    list.addAll(elems);
  }

  public List<ListFilterElem> getList()
  {
    return filterInterface.doFilter(list);
  }

  public void setFilter(String filter)
  {
    filterInterface.setFilter(filter);
  }

  public String getFilter()
  {
    return filterInterface.getFilter();
  }
}

Used class Mask: 二手面膜:

public class Mask implements MaskInterface
{
  private Integer ensureInteger(Object o) throws Exception
  {
    if (o == null)
    {
      return null;
    }
    else if (o instanceof Integer)
    {
      return (Integer) o;
    }
    else if (o instanceof String)
    {
      return new Integer((String) o);
    }
    else
    {
      throw new Exception("cannot convert " + o.getClass() + " to Integer");
    }
  }

  @Override
  public String getMask(Object o)
  {
    try
    {
      switch (ensureInteger(o))
      {
        case 1: return "first line";
        case 2: return "second line";
        case 3: return "third line";
        default: return "unknown";
      }
    }
    catch (Exception e)
    {
      return e.getMessage();
    }
  }
}

Used class ValueMask: 二手课ValueMask:

public class ValueMask
{
  private MaskInterface maskInterface;

  public ValueMask(MaskInterface maskInterface)
  {
    this.maskInterface = maskInterface;
  }

  public String getMask(Object o)
  {
    return maskInterface.getMask(o);
  }
}

Used class TestAction: 二手的类TestAction:

@ManagedBean
@SessionScoped
public class TestAction
{
  private ListFilter listFilter;
  private String variable;

  public ListFilter getListFilter()
  {
    if (listFilter == null)
    {
      listFilter = new ListFilter(new TestFilter());
      listFilter.addListElem(new TestListFilterElem(1, Arrays.asList(new String[]{"this", "is", "the", "first", "list"})));
      listFilter.addListElem(new TestListFilterElem(2, Arrays.asList(new String[]{"second", "list"})));
      listFilter.addListElem(new TestListFilterElem(3, Arrays.asList(new String[]{"(brackets", "(in", "(brackets)))"})));
    }
    return listFilter;
  }

  public ValueMask getValueMask()
  {
    return new ValueMask(new Mask());
  }
}

Maven dependencies for mojarra: Mojarra的Maven依赖项:

<dependency>
  <groupId>com.sun.faces</groupId>
  <artifactId>jsf-api</artifactId>
  <version>2.2.1</version>
</dependency>
<dependency>
  <groupId>com.sun.faces</groupId>
  <artifactId>jsf-impl</artifactId>
  <version>2.2.1</version>
</dependency>

Maven dependencies for myfaces: Myfaces的Maven依赖项:

<dependency>
  <groupId>org.apache.myfaces.core</groupId>
  <artifactId>myfaces-api</artifactId>
  <version>2.1.10</version>
</dependency>
<dependency>
  <groupId>org.apache.myfaces.core</groupId>
  <artifactId>myfaces-impl</artifactId>
  <version>2.1.10</version>
</dependency>

The Stacktrace if using mojarra: Stacktrace(如果使用mojarra):

SEVERE: Servlet.service() for servlet [FacesServlet] in context with path [/TestJsfComponents] threw exception [null] with root cause
java.lang.NullPointerException
  at java.util.Hashtable.put(Hashtable.java:542)
  at java.beans.FeatureDescriptor.setValue(FeatureDescriptor.java:194)
  at com.sun.faces.facelets.tag.composite.AttributeHandler$CCAttributePropertyDescriptor.getValue(AttributeHandler.java:210)
  at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler$CompositeComponentMetaRuleset$CompositeMetadataTarget.getPropertyType(CompositeComponentTagHandler.java:464)
  at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler$CompositeComponentRule.applyRule(CompositeComponentTagHandler.java:540)
  at com.sun.faces.facelets.tag.MetaRulesetImpl.finish(MetaRulesetImpl.java:173)
  at javax.faces.view.facelets.MetaTagHandler.setAttributes(MetaTagHandler.java:127)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.setAttributes(DelegatingMetaTagHandler.java:102)
  at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.setAttributes(CompositeComponentTagHandler.java:245)
  at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyNextHandler(CompositeComponentTagHandler.java:181)
  at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:190)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
  at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
  at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:190)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
  at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
  at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:190)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
  at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
  at com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)
  at com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)
  at com.sun.faces.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:161)
  at com.sun.faces.application.view.FaceletViewHandlingStrategy.buildView(FaceletViewHandlingStrategy.java:980)
  at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:99)
  at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
  at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
  at javax.faces.webapp.FacesServlet.service(FacesServlet.java:647)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
  at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
  at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
  at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
  at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
  at java.lang.Thread.run(Thread.java:722)

The Question: 问题:

If I use myfaces, the component is rendered and working (filtering elements is reducing the list by ajax on the fly), but if I use mojarra (even mojarra is 2.2.1 and myfaces is just 2.1.10), the component is not rendered due to the stacktrace shown above. 如果我使用myfaces,则该组件可以渲染并正常工作(过滤元素通过ajax迅速减少列表),但是如果我使用mojarra(即使mojarra为2.2.1,而myfaces也仅为2.1.10),则该组件不是由于上面显示的stacktrace而呈现。

Why is this so and what can I do to make mojarra work with this composite component? 为什么会这样,我该怎么做才能使mojarra与该复合组件一起工作?

Annotations: 注释:

The complexity of this usage (filter classes and such) is due to using this component in another composite component later, therefore the interfaces and implementations mentioned above are necessary. 这种用法(过滤器类等)的复杂性是由于稍后在另一个复合组件中使用此组件所致,因此上述接口和实现是必需的。

After a while I found the problem: 一段时间后,我发现了问题:

<composite:attribute name="valueMask" required="false" type="" />

The attribute type is empty. 该属性类型为空。 Seems like myfaces forgives this and mojarra does not. 好像myfaces宽恕了这一点,而mojarra却没有。 I'd prefer a better stacktrace (message) for such an error. 对于这种错误,我希望使用更好的stacktrace(消息)。

Nevertheless, removing type solved the problem (in my case I gave type the full qualified class I needed). 不过,删除类型可以解决问题(在我的情况下,我为类型提供了所需的完全合格的类)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM