使用 JavaScript 框架注册 JSF 自定义组件
Registering JSF custom components with JavaScript framework
我正在努力将前端组件的 JavaScript 框架 (Aurelia) 集成到我们现有的 JSF 应用程序中。我正在使用 JSF 渲染器将自定义标签放入输出中,例如:
@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);
}
}
问题是在初始化 JS 框架时我必须知道需要 bootstrapped 哪些自定义标签。起初我尝试在服务器端执行此操作,方法是将标记名作为 属性 添加到我的 JSF 前端组件 class,将其设置在自定义渲染器中并遍历 JSF 组件树以获取列表:
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 + "'";
}
}
但是我发现 JSF 呈现部分页面的顺序并不完全可以预测,有时 walkRecursive
在 setTagName
之前被调用。
现在我已经决定在每个自定义标签旁边呈现一个 <script>
片段,以将标签列表保存到 bootstrap 客户端,但这并不理想。谁能给我一个更优雅的解决方案?
我找到了一种在服务器端维护组件列表的方法。我没有在渲染器中将标签名称设置为 bootstrap,它可以随时调用,我将其设置在 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
@ManagedBean
@RequestScoped
class FrontendBootstrapHandler {
public String getTagList() {
List<String> tags = walkRecursive(FacesContext.getCurrentInstance().getViewRoot());
return "'" + String.join("','", tags + "'";
}
}
我正在努力将前端组件的 JavaScript 框架 (Aurelia) 集成到我们现有的 JSF 应用程序中。我正在使用 JSF 渲染器将自定义标签放入输出中,例如:
@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);
}
}
问题是在初始化 JS 框架时我必须知道需要 bootstrapped 哪些自定义标签。起初我尝试在服务器端执行此操作,方法是将标记名作为 属性 添加到我的 JSF 前端组件 class,将其设置在自定义渲染器中并遍历 JSF 组件树以获取列表:
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 + "'";
}
}
但是我发现 JSF 呈现部分页面的顺序并不完全可以预测,有时 walkRecursive
在 setTagName
之前被调用。
现在我已经决定在每个自定义标签旁边呈现一个 <script>
片段,以将标签列表保存到 bootstrap 客户端,但这并不理想。谁能给我一个更优雅的解决方案?
我找到了一种在服务器端维护组件列表的方法。我没有在渲染器中将标签名称设置为 bootstrap,它可以随时调用,我将其设置在 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
@ManagedBean
@RequestScoped
class FrontendBootstrapHandler {
public String getTagList() {
List<String> tags = walkRecursive(FacesContext.getCurrentInstance().getViewRoot());
return "'" + String.join("','", tags + "'";
}
}