2011-09-23 4 views
10

Ho creato una consuetudine ISO tempo Data Converter:Come impostare le proprietà del convertitore per ciascuna riga di un datatable?

public class IsoDateTimeConverter implements Converter, StateHolder { 

    private Class type; 
    private String pattern; 

    private boolean transientValue = false; 

    public void setType(Class type) { 
     this.type = type; 
    } 

    public void setPattern(String pattern) { 
     this.pattern = pattern; 
    } 

    @Override 
    public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException { 
     if (StringCheck.isNullOrEmpty(value)) { 
      throw new ConverterException("value not specified"); 
     } 

     try { 
      if (IsoDate.class.equals(type)) { 

       if (WebConst.ISO_DATE_NONE.equals(value)) { 
        return IsoDate.DUMMY; 
       } else { 
        //TODO User spezifische TimeZone auslesen 
        return new IsoDate(value, TimeZone.getDefault().getID()); 
       } 

      } else if (IsoTime.class.equals(type)) { 

       if (WebConst.ISO_TIME_NONE.equals(value)) { 
        return IsoTime.DUMMY; 
       } else { 
        //TODO User spezifische TimeZone auslesen 
        return new IsoTime(value, TimeZone.getDefault().getID()); 
       } 

      } else if (IsoTimestamp.class.equals(type)) { 

       if (WebConst.ISO_TIMESTAMP_NONE.equals(value)) { 
        return IsoTimestamp.DUMMY; 
       } else { 
        //TODO User spezifische TimeZone auslesen 
        return new IsoTimestamp(value, TimeZone.getDefault().getID()); 
       } 

      } else { 
       throw new ConverterException("value not convertible"); 
      } 
     } catch (Exception e) { 
      throw new ConverterException(e.getMessage()); 
     } 
    } 

    @Override 
    public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException { 
     if (value == null) { 
      throw new ConverterException("value not specified"); 
     } 

     if (IsoDate.class.equals(value)) { 
      IsoDate isoDate = (IsoDate) value; 

      if (isoDate.isDummy()) { 
       return WebConst.ISO_DATE_NONE; 
      } else { 
       //TODO User spezifische TimeZone auslesen 
       return isoDate.toString(pattern, TimeZone.getDefault().getID(), false); 
      } 

     } else if (IsoTime.class.equals(value)) { 
      IsoTime isoTime = (IsoTime) value; 

      if (isoTime.isDummy()) { 
       return WebConst.ISO_TIME_NONE; 
      } else { 
       //TODO User spezifische TimeZone auslesen 
       return isoTime.toString(pattern, TimeZone.getDefault().getID(), false); 
      } 

     } else if (IsoTimestamp.class.equals(value)) { 
      IsoTimestamp isoTimestamp = (IsoTimestamp) value; 

      if (isoTimestamp.isDummy()) { 
       return WebConst.ISO_TIMESTAMP_NONE; 
      } else { 
       //TODO User spezifische TimeZone auslesen 
       return isoTimestamp.toString(pattern, TimeZone.getDefault().getID(), false); 
      } 

     } else { 
      throw new ConverterException("value not convertible"); 
     } 
    } 

    @Override 
    public Object saveState(FacesContext context) { 
     return new Object[]{type, pattern}; 
    } 

    @Override 
    public void restoreState(FacesContext context, Object state) { 
     type = (Class) ((Object[]) state)[0]; 
     pattern = (String) ((Object[]) state)[1]; 
    } 

    @Override 
    public boolean isTransient() { 
     return transientValue; 
    } 

    @Override 
    public void setTransient(boolean transientValue) { 
     this.transientValue = transientValue; 
    } 
} 

e io uso il Converter come <mh:IsoDateTimeConverter> nella seguente prospettiva:

<p:dataTable value="#{imports.list}" var="item"> 
    <p:column> 
     <h:outputText value="#{item.balanceDate}" immediate="true"> 
      <mh:IsoDateTimeConverter type="#{webConst.ISO_DATE_CLASS}" pattern="#{webConst.ISO_DATE_FORMAT}"/> 
     </h:outputText> 
    </p:column> 
</p:dataTable> 

Il problema è che quando ho aperto questo punto di vista, tutte le le proprietà sono impostate nella mia classe Converter una sola volta e quindi il datatable esegue il rendering e converte i valori in base alle proprietà iniziali.

I expected che le proprietà sono impostate su una base per-riga. Come posso raggiungere questo obiettivo?

risposta

24

Al punto, ci si aspettava che le proprietà del convertitore venissero impostate ogni volta che una riga databile è rappresentata. Questo non è davvero vero. JSF creerà solo una istanza di convertitore per componente quando la vista deve essere costruita, non creerà/ripristinerà il convertitore ogni volta che la riga viene sottoposta a rendering.

Ci sono diversi modi per farlo funzionare.

  • Far passare gli attributi dinamici come <f:attribute> del componente e lasciare che il Converter intercetta su questo. È possibile trovare un esempio qui: JSF convertDateTime with timezone in datatable. Questo può quindi essere utilizzato come

    <h:outputText value="#{item.balanceDate}"> 
        <f:converter converterId="isoDateTimeConverter" /> 
        <f:attribute name="pattern" value="#{item.pattern}" /> 
    </h:outputText> 
    

  • Usare una funzione EL invece di un Converter. È possibile trovare un esempio qui: Facelets and JSTL (Converting a Date to a String for use in a field). Questo può quindi essere utilizzato come

    <h:outputText value="#{mh:convertIsoDate(item.balanceDate, item.pattern)}" /> 
    

  • Bind il convertitore e datatable di DataModel come una proprietà dello stesso bean gestito. In questo modo sarai in grado di impostare le proprietà del convertitore in base ai dati della riga prima di restituirlo. Ecco un esempio di kickoff di base sulla base di componenti JSF standard e standard di DateTimeConverter (dovrebbe funzionare altrettanto bene su componenti primefaces e con il convertitore di ordinazione):

    <h:dataTable value="#{bean.model}" var="item"> 
        <h:column> 
         <h:outputText value="#{item.date}" converter="#{bean.converter}" /> 
        </h:column> 
    </h:dataTable> 
    

    con

    @ManagedBean 
    @ViewScoped 
    public class Bean implements Serializable { 
    
        private List<Item> items; 
        private DataModel<Item> model; 
        private DateTimeConverter converter; 
    
        @PostConstruct 
        public void init() { 
         items = Arrays.asList(
          new Item(new Date(), "dd-MM-yyyy"), 
          new Item(new Date(), "yyyy-MM-dd"), 
          new Item(new Date(), "MM/dd/yyyy")); 
         model = new ListDataModel<Item>(items); 
         converter = new DateTimeConverter(); 
        } 
    
        public DataModel<Item> getModel() { 
         return model; 
        } 
    
        public Converter getConverter() { 
         converter.setPattern(model.getRowData().getPattern()); 
         return converter; 
        } 
    
    } 
    

    (classe Item è solo un fagiolo con due proprietà Date date e String pattern)

    questo implica che

    23-09-2011
    2011-09-23
    09/23/2011


  • Usa OmniFaces<o:converter> invece. Supporta la valutazione del tempo di rendering di EL negli attributi. Vedi anche the <o:converter> showcase example.

    <h:outputText value="#{item.balanceDate}"> 
        <o:converter converterId="isoDateTimeConverter" pattern="#{item.pattern}" /> 
    </h:outputText>