JSF 2.0: Render campi del modulo con i dati iniziali usando i fagioli di richiesta con ambito (per dati specifici server di aggiornamento al componente corrente)

StackOverflow https://stackoverflow.com/questions/3812685

Domanda

Un caso abbastanza normale:

Abbiamo un componente composito 'portlet' che ha due stati: espansi e compressi. Portlet Start come ampliato, ma l'utente li può crollare cliccando su di essi. Questo stato deve essere salvato alla sessione, in modo che una volta che l'utente aggiorna la pagina o naviga verso un nuovo, i portlet ricordo se sono espansi / crollata.

Questo è il nocciolo del problema :? Come ti effettivamente implementare tale in un componente, di risparmio dello stato che può essere inserito sulla pagina più volte

Alcuni di fondo / idee:

Implementazione stato di risparmio per un portlet potrebbe essere raggiunto facilmente usando un session bean con ambito. numero fisso anche di portlet potrebbe essere sostenuto creando un numero fisso di fagioli di sessione con scope o dichiarando proprietà diverse in un fagiolo. Comunque, io non voglio menzionare anche perché questi approcci è male.

La mia idea iniziale per questo era quello di creare una mappa (o qualche struttura dell'oggetto) sotto un'unica session bean per contenere gli stati per tutti i portlet. Tuttavia, non posso fare riferimento direttamente a questi dati da JSF (in modo che JSF inoltre aggiornarle). Ho considerato crei una specifica getter / setter per recuperare / aggiornare il giusto valore nella mappa, ma non è possibile in quanto non ci sono dati identificativi durante l'esecuzione di getter e setter.

Tuttavia, è probabilmente chiaro che ho bisogno di salvare gli stati in una session bean. Posso fare lo stato di risparmio abbastanza facilmente inviando un modulo con f:ajax e l'esecuzione di un metodo speciale utilizzando listener ei dati presentati. Al fine di supportare più istanze di componente, ho potuto utilizzare (più istanze di) un fagiolo richiesta con ambito per gestire ogni crollo espansione /. Tuttavia, al fine di inserire in realtà i dati che identifica il portlet e il suo stato, ho bisogno di prima inserto su campi modulo a render-tempo.

Quindi, come fornire in realtà ogni portlet con dati corretti su render-tempo (in realtà solo stato booleano / enum in questo caso, ma si consideri un caso in cui devono essere maneggiati più dati)?

Sembra che:

  • h:inputHidden e h:inputText non supportano l'impostazione valore iniziale diverso rispetto al valore di attributo (che indicherebbe #{portletBean.portletState}).
  • Non posso auto-caricare i fagioli di richiesta con i valori iniziali direttamente sui loro ora di creazione, in quanto non vi sono informazioni di identificazione disponibili.

Ancora una volta ci si sente come mi manca qualcosa ... puntatori?

suppongo, almeno una delle risposte sarebbe quella di utilizzare UIComponent piuttosto che componenti in composito, ma vorrei mantenere questo come componente composito in quanto contiene un sacco di elementi HTML prime.

Aggiornamento:

  • C'è un piuttosto simile domanda , con il suggerimento per l'uso di fagioli vista con ambito. Non credo che questo è fattibile qui, tuttavia.
È stato utile?

Soluzione 3

ho usato un precedentemente risolto hack per chiamare un metodo di fagioli da JS :

Creata una forma invisibile vuoto, con h:commandButton e f:ajax suo interno chiamando listener.

Creato un pulsante separato per lanciare l'evento di espansione / compressione. Da quel tasto avviare il metodo javascript, che anima l'espansione / compressione e allo stesso tempo fa clic sul pulsante nascosto all'interno del modulo. Tutti i dati necessari vengono inviati utilizzando l'attributo listener. Listener rivolge un session bean, che controlla / aggiorna una mappa di stati, identificato dal client ID del componente.

Questo è abbastanza semplice, chiedo perché non mi rendevo conto che eariler ...

Tuttavia, è ancora lontano dall'essere perfetto e non risponde come i fagioli di richiesta con ambito potrebbero essere avviate con i valori di default di usarli come deposito modulo / trasporto.

Altri suggerimenti

Ho un paio di hack possibili per questo. Io li posterò qui, ma non credo che queste sono davvero la strada da percorrere:

usare JavaScript per i campi del modulo set con i dati corretti direttamente dopo il rendering:

window.addEvent('domready', function() {
    var portletState = '#{portletBean.getPortletState(cc.attrs.clientId)}';
    // find the field and set the data...
});

Si sente veery hacky. Io non voglio prendere questa strada.

mappa attributo Usa componente per contenere i dati:

<cc:interface>
    <cc:attribute name="portletState" default="#{portletBean.getPortletState(cc.attrs.clientId)}" />
</cc:interface>

Access che dal codice:

public void stateChangedCallback(String clientId) {
    UIComponent component = FacesContext.getCurrentInstance().getViewRoot().findComponent(clientId);
    String state = (String) component.getAttributes().get("portletState");
}

Inoltre, non si sente bene. Anche io non sono sicuro se funziona (si può effettivamente utilizzare EL in default-attributo).

Usa componente attributo mappa per contenere i dati, fornendo essa quando si chiama il componente:

<portlet:portlet id="specificPortlet">
    <f:attribute name="portletState" value="#{portletBean.getPortletState(component.clientId)}" />
</portlet:portlet>

Anche in questo caso, molto goffo e duplica il proprio codice.

È possibile farlo utilizzando taglibs, è possibile passare parametri in tag:

aggiungere quanto segue al vostro taglib:

<tag>
    <tag-name>date</tag-name>
    <source>components/date.xhtml</source>
</tag>

Quindi qui è il contenuto di componenti / date.xhtml

<ui:composition name="date_template">
    <h:panelGrid id="#{id}Panel" columns="1" border="0" cellpadding="0" cellspacing="0">
        <rich:calendar immediate="true" id="#{id}" popup="true" datePattern="dd.MM.yyyy"
                        enableManualInput="true" showApplyButton="true" cellWidth="12px" cellHeight="11px" style="width:100px"
                        value="#{dateForm.date}" required="#{required}" readonly="#{readonly}" validator="#{dateForm.validateDate}">
            <a4j:support event="onchanged" reRender="#{id}Panel,#{reRenderDate}"/>
            <ui:insert />
        </rich:calendar>

        <rich:message for="#{id}" errorClass="error" />
    </h:panelGrid>
</ui:composition>

E poi si utilizza questo tipo:

<adse:date id="dateTransfert" required="true"
           dateForm="#{dossierBean.dateTransfert}"
           readonly="false" reRenderDate="montantAncien,montantNouveau,montantEmolument">
     <a4j:support event="oninputblur" reRender="dateTransfertPanel,montantAncien,montantNouveau,montantEmolument"/>
</adse:date>

In questo caso, dateForm viene passato, questo è un oggetto, e nel taglib usiamo proprietà dell'oggetto (dateForm.date). Da notare anche la. che può essere usato per includere altri elementi nel XHTML

Quindi, si potrebbe passare nel contesto per ogni portlet. Si potrebbe anche fare questo standard avendo portletBean come una superclasse che definisce il metodo getPortletState ().

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top