2016-04-11 8 views
2

Ich arbeite daran, ein JavaScript-Framework (Aurelia) für Frontend-Komponenten in unsere bestehende JSF-Anwendung zu integrieren. Ich verwende JSF-Renderer die benutzerdefinierten Tags in die Ausgabe zu platzieren, z.B .:Registrieren von JSF-eigenen Komponenten mit JavaScript-Framework

@FacesRenderer(componentFamily = "frontend.component", rendererType = "frontend.mytag") 
public class MyTagRenderer extends Renderer { 

    @Override 
    public void encodeEnd(FacesContext context, UIComponent component) throws IOException { 
     final String tag = "my-tag"; 
     int id = (Integer) component.getAttributes().get("id"); 
     ResponseWriter writer = context.getResponseWriter(); 
     writer.startElement(tag, component); 
     writer.writeAttribute("id.bind", id, null); 
     writer.endElement(tag); 
    } 
} 

Das Problem ist, dass während der JS Rahmen der Initialisierung Ich muss wissen, welche benutzerdefinierten Tags Bootstrap werden müssen. Zuerst habe ich versucht, diese Server-Seite tun, durch Zugabe des tagname als Eigenschaft meiner JSF-Frontend-Komponenten-Klasse, es in dem benutzerdefinierten Renderer Einstellung und den JSF-Komponentenbaumes zu Fuß eine Liste zu erhalten:

class MyTagRenderer { 
    public void encodeEnd(FacesContext context, UIComponent component) { 
     ... 
     ((FrontendComponent) component).setTagName("my-tag:); 
    } 
} 

@ManagedBean 
@RequestScoped 
class FrontendBootstrapHandler { 
    public String getTagList() { 
     List<String> tags = walkRecursive(FacesContext.getCurrentInstance().getViewRoot()); 
     return "'" + String.join("','", tags + "'"; 
    } 
} 

aber ich festgestellt, dass die Reihenfolge, in der JSF Teile der Seite rendert, nicht vollständig vorhersehbar ist, und manchmal wurde die walkRecursive vor setTagName aufgerufen.

Für jetzt habe ich mich darauf festgelegt, ein <script> Snippet neben jedem benutzerdefinierten Tag zu rendern, um die Liste der Tags zum Bootstrap Client-Seite zu halten, aber das ist kaum ideal. Kann mir jemand eine elegantere Lösung anbieten?

+1

Ich habe einen Blick auf Aurelia und scheint ein Framework ähnlich AngularJs, die eine komplette MVC-Framework ist, nicht wie jQuery, die nur Syntax Zucker zum JS hinzugefügt. JSF macht dasselbe wie Aurelia, aber auf der Serverseite. Wenn Sie JSF durch Aurelia ersetzen, würde ich vorschlagen, dass Sie ganze Ansichten ersetzen und richtige Controller (könnte Spring MVC oder ein anderes Framework sein) auf der Serverseite platzieren, statt die verwalteten Beans zu verwenden. Die Skripte, die Sie schreiben, ersetzen die Managed Bean-Funktionalität. Sonst scheint es zu Kopfschmerzen zu kommen, wenn man versucht, beide gleichzeitig zu mischen. –

+1

@Xtreme: JSF/Facelets können so gut verwendet werden, um (zustandslose) HTML-Ansichten für andere Frameworks zu generieren. Basierend auf dem Frageverlauf scheint OP mit JAX-RS vertraut zu sein, so dass dies gegenüber Feder-MVC-REST-Controllern empfohlen wird (nur für den Fall). – BalusC

+0

Alles, was ich weiß, aber ich kann nicht eine 10 Jahre alte Legacy-Anwendung von JSF über Nacht auf JavaScript umschreiben. Obwohl es sich als unpraktisch erweist, werde ich beides vorläufig brauchen. –

Antwort

0

Ich habe einen Weg gefunden, um die Liste der Komponenten serverseitig zu pflegen. Anstatt den Tag-Namen in den Renderer Bootstrap Einstellung, die jederzeit aufgerufen werden kann, habe ich es in einem ComponentHandler:

my.taglib.xml

<tag> 
    <tag-name>my-tag</tag-name> 
    <attribute> 
     <name>id.bind</name> 
     <required>true</required> 
     <type>java.lang.Integer</type> 
    </attribute> 
    <component> 
     <component-type>frontend.component</component-type> 
     <renderer-type>frontend.renderer</renderer-type> 
     <handler-class>frontend.FrontendComponentHandler</handler-class> 
    </component> 
</tag> 

FrontendComponentHandler.java

public class FrontendComponentHandler extends javax.faces.view.facelets.ComponentHandler { 

    public FrontendComponentHandler(ComponentConfig config) { 
     super(config); 
    } 

    @Override 
    public void onComponentCreated(FaceletContext ctx, UIComponent c, UIComponent parent) { 
     FrontendComponent component = (FrontendComponent) c; 
     component.setTagName(tag.getLocalName()); 
    } 
} 

FrontendBootstrapHandler.java