| Author |
Message |
|
|
Yes, sorry I went back and edited the definition behind your back to remove the "locals" which used to be there from cut 'n paste
Yes, the id, derived from the paths of rsf:id throught the template, will remain... the idea is that every element in the document will get a unique id assigned that gets touched by IKAT.
If you think it would be useful I could put in an option to suppress them when we have Renderer Reform in 0.7.
|
 |
|
|
Oops! I forgot about the actual "rendering" part of handling AJAX requests...
I suggest for now you adopt the following Very Bad Practice and derive from the HTMLRenderSystem which is responsible for handling leaf components for IKAT.
Like this:
Code:
public class MultiRenderSystem extends HTMLRenderSystem {
public void setViewParameters(ViewParameters viewparams) {
this.viewparams = viewparams;
}
public void setTemplateExtensionInferrer(TemplateExtensionInferrer inferrer) {
this.inferrer = inferrer;
}
public String getDeclaration() {
String extension = inferrer.inferTemplateExtension(viewparams);
return extension.equals("html")? super.getDeclaration() : "";
}
}
Then declare this in your requestContext.xml file with the following definition:
Code:
<bean id="renderSystem"
class="yourpackage.MultiRenderSystem">
<property name="staticRenderers" ref="staticRenderers" />
<property name="viewParameters" ref="viewParameters" />
<property name="templateExtensionInferrer" ref="templateExtensionInferrer"/>
</bean>
I'll sort you out something better for 0.6.2/0.7 - in particular note that HTMLRenderSystem will be blasted to small pieces in 0.7 so I won't be able to avoid improving it
Yes, I'd generally forgotten about the RenderSystem aspect of AJAX - but as long as you stick to the non-HTML-specific types of component - UIOutput, UIVerbatim and UIBranchContainer, you should be fine.
|
 |
|
|
You only need to implement a TemplateExtensionInferrer (interface) and redeclare templateExtensionInferrer (bean). That is assuming you're happy with the default choice of baseDirectory.
If I understand you right, the point of confusion is whether the bean references from viewTemplateResolver are happy to resolve "up" the stack to your own tEI, and the answer is yes they are - overrides happen on a bean-by-bean basis.
|
 |
|
|
OK, you're a bit stuck here because you have dependencies which are "back to front" - you have an application scope bean, simplepager, whose dependency is something with a shorter lifetime than itself, the pageraction.
While this is actually technically possible (using the RSACBridgeProxy), this is something you have to be extremely careful with since it is in a proper sense logically invalid (although given virtually every access to the context will be within the scope of a valid RSAC request there is little chance that it will go wrong by "blowing up" by findiing nothing).
There are two answers to this - i) move simplepager into request scope, so you can wire the dependence properly. ii) make a proxy to the PagerAction in application scope - take a look at http://www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?page=RSACBridgeProxy for explanation.
This "pager" business is really quite knotty in terms of the scoping issues, and I'm looking forward to us coming up with some good solutions for it You may want to look at the ServerSide thread where this issue came up http://www.theserverside.com/news/thread.tss?thread_id=40127#207520 since it's really quite awkward whether you want to put this state in the URL, or in the "model". Right now you are opting for putting it in the model, which is fine, but we will need to think about how to make a smooth transition from one scheme to the other.
|
 |
|
|
You have more than one item with the same value!!! This is a great moral crime!
Seriously, the "value" really is meant to be the "unique" representation of what the selection value actually is. If you want to "de-normalise" it later, you could do this in the model, or you could have RSF do it with a resolver or darreshaper. But really, I don't think what you want to do is even supported by HTML, let alone RSF....
|
 |
|
|
Oh you can leave it in the HTML, since it's useful for previewing. It will just get overwritten once the control is rendered proper. But after thinking about it, I don't suppose letting people write optionlists statically would be any problem, I'll put it in for 0.6.2-dev
PS - on second thoughts I think I won't - this would mean I needed to parse in that part of the HTML template and interpret it, which would be some way off current RSF idioms....
|
 |
|
|
OK - you can see a pure-Java example of a (slightly complex) selection control in the last page of the Hibernate Cookbook http://www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?page=HibernateCookBook_4 (in the recipe editing page, just over half way down).
The key point is that UISelect is a "cluster" control, a composite of two UIBoundLists (representing the "palette" of selections, and their names) and a UIBound representing the submitted value. All of these fields will need to be set or else nothing can happen - if you look at the last "constructor" in UISelect.java you can see a more basic example of a fully-filled-out submitting control.
So the first problem in your example is that you have not set optionlist. Unfortunately there is no model in RSF whereby it will pick up a statically listed set of options from the HTML - sorry! Now I see you trying to do this of course I can see that might be rather cool, but it never struck me before Perhaps for 0.7 or so when we have "rendering reform".
So, to get your example to work, you will need to add some lines like
UIBoundList values = new UIBoundList();
values.setValue(new String[] {"10", "20", "50", "100"};
show.selection.optionlist = values;
and similar lines for the optionnames.
Although, for the optionnames, if you want to be really cool you can write in the same string array into optionnames.setValue and use a resolver !
Code:
show.selection.optionnames.resolver = new BeanResolver() {
public String resolveBean(Object bean) {
return "Show " + bean;
}};
If you want this resolver to be configurable you could instead declare it as a Spring bean in the context, and instead make the resolver be an ELReference to it.
I'll fix the code path you triggered to put in a more informative message.
|
 |
|
|
RSF version 0.6.1 is now released! This is synchronized with version 1.1.1 of J-ServletUtil and PonderUtilCore.
New in this version are
* Improved Maven build idiom for sample apps
* Pea proxying using the "get()" idiom
* Improved error handling
* Greater flexibility in view template resolution
* New components UIAnchor and UIVerbatim
* Numerous bug fixes, especially in rendering and all-round performance improvements
Enjoy!
All documentation is on the main project site http://www2.caret.cam.ac.uk/rsfwiki/
|
 |
|
|
|
You forgot to implement the ViewParamsReporter interface in your ViewProducer.
|
 |
|
|
|
49.0 is the class file version for JDK 1.5.0 - this error is probably caused by building with 1.5 and deploying on a 1.4 JVM.
|
 |
|
|
OK, point 1: Yes, in general the "colon"ed tag will be the one on which branching works. So the code you have in your second example is correct - you need a colon tag to perform the selection of the td element, and then a further non-colon tag if you want any components inside that.
There is a tiny exception to this which is the special rsf:id of "payload-component". This deals with the quite common case where you have a leaf component you want to switch in and out, but the rsf component peer is on some lower level. For example,
<div rsf:id="link"> spacing stuff you want around the link <a rsf:id="payload-component" href="#">link text</a> stuff after the link</div>
But this trick does not work with branch components. To the best of my knowledge
2. The "Full ID" algorithm is explained in the wiki in the page on IDs. You can also refer to the docs in the code for getFullID() in UIComponent
|
 |
|
|
The key customisation point here is the viewTemplateResolver - the default definition in RSF from blank-applicationContext.xml is as follows:
Code:
<bean id="viewTemplateResolver"
class="uk.org.ponder.rsf.templateresolver.BasicTemplateResolver">
<property name="baseDirectory">
<value>/content/templates/</value>
</property>
<property name="consumerInfo">
<ref bean="consumerInfoProxy" />
</property>
</bean>
I'm imagining this will be prime grounds for user-defined customisation, since TemplateResolver is a prime RSF OLI:
Code:
public interface TemplateResolver {
public ViewTemplate locateTemplate(ViewParameters viewparams);
}
As you've noticed, the BasicTemplateResolver operates a simple 2-step strategy which first looks for any ConsumerRequestInfo which might provide a template file prefix, and then looks up a file with named after the viewId (possibly with prefix) in the baseDirectory with the .html suffix.
From what you're saying, it sounds like you will want to look up different viewIds to different suffixes. This currently isn't implemented but as you see BasicTemplateResolver is fairly straightforward and easy to provide alternate implementations. That said, we should talk about how you would like to specify your mappings from viewID to extension (I guess in some kind of XML file) and I will refactor BasicTemplateResolver to make it easier for people to provide their own. Until you came along I had no real idea what sort of template resolution people would actually want so I left this stuff quite basic
Just in time to get this in for 0.6.1.
|
 |
|
|
Cool, glad you're getting with the "request-scope flow"
Yes, putting your value and method bindings onto the same bean is probably pretty bad, but don't worry about it for now This is the sort of design that you were pretty much forced to in "old" frameworks like JSF and the Spring Annotations stuff where it was difficult to deal with different beans in the request scope in a coordinated way. You'll have heard the recommendation from JSF folks to use "one bean - one page" which was pretty much the only sensible way to "get the framework out of your hair" as quickly as possible.
A current nasty "anti-pattern" IMO you can see with some of the recent 2.0 Spring annotations stuff, where people say things like "we set these values in this bean, and then we 'tell it to persist itself'". This is a mess, since naturally the service of persisting something is separate from the business function of your model (even if you insulate the details of what it actually does by creating a "DAO" type interface), and it's completely backward to inject your persistence service into the bean, rather than hand your bean to the persistence service.
Once your design gets a bit more complicated, or you start using some kind of persistence, you'll probably appreciate splitting up your logic and state a bit more - the idea behind RSF is that, for a fully "bean-ridden" design that it lets you work with the beans you already (want to) have rather than be forced to just create special "beans" for dealing with the UI (i.e. on a per-page basis). However, it doesn't stop you creating extra beans to form a JSF-like "controller" layer if you want/need to. And if you didn't have any beans to start with, you can't avoid making some new ones in any case
But no, beans that you "just made for the UI" just aren't beans in my book.
Yes, getting out of session scope produces apps that aren't just more efficient, but give a better user experience too. So great to hear you're getting up the curve so quickly
|
 |
|
|
Actually only the 2nd way is supported in RSF - in general you may not just apply random fields to forms and expect to decode them in the raw on the next cycle. In general what is encoded in an RSF form is pure operations on the bean model and shouldn't be thought of as a set of parameters at all. This may seem a bit odd, but it is the natural result of separating URL state (held in ViewParameters objects) and application state (held in the model) which is correct given HTTP semantics as well as the way most portals (except for a certain one that we know well  expect to work.
So, that out of the way, in the example below, you have set up your "topicdisplay" bean which will have its "title" property set when the form is submitted. What you are missing is the "action" which the UICommand object will trigger, which needs to be on some kind of request bean, which, probably will need to be able to see the topicdisplay request bean. This sort of setup will be familiar to JSF people, although in RSF it is a bit cleaner because i) the request beans are managed by Spring (or something near it), and ii) the really messy "component" layer from JSF is gone completely. In RSF, "topicdisplay" is considered as part of YOUR model and the values are applied to it directly, and it's your job to figure out what to do with it.
So, you need to set up the bean that handles the action, and get it connected to the topicdisplay bean. There are (at least) two ways of doing this.
BASIC WAY:
One way, more similar to the JSF way, is to set up the association "statically" in your requestContext.xml file - e.g.
Code:
<bean id="edithandler" class="MyEditHandler">
<property name="editTarget" ref="topicdisplay"/>
</bean>
<bean id="topicdisplay" class="MyTopicDisplay"/>
So, when your POST response comes in, these two beans will be created in the request, wired together, the incoming request values will be applied, THEN your action is invoked.
In your case, you'd probably make a "saveEdit()" method on MyEditHandler, and add the method binding to the saveedit control:
UICommand.make(form, "saveedit", "#{edithandler.saveEdit}");
Cooler, more dynamic way
When you are in a more complicated situation, perhaps with an ORM solution involved which stops you from having just the one bean in scope that you are talking about, you can't set up the link between the action bean and the data bean in a static way as before.
To deal with this situation, RSF allows you to set up the association dynamically by encoding a special binding into the form. The syntax for this looks like this:
Code:
RSFUtil.addBasicFormParameter(parent,
new UIELBinding("#{messageEditBean.actionKey}",
viewparams.action));
So, the first argument to the UIELBinding constructor is the target of the binding, that is an EL path that will be written. The second argument is a value that will be written to it.
If the second argument is just a plain value, you can just think of this as a fancy model-aware way of encoding a hidden field - it's the basic way to get extra context into the handler of the POST on the other side. However, the second argument could also be another EL reference, which I'm sure you can see the cool potential of - the property for the first argument will be "wired" to the property for the second argument, letting you, for example, "inject" a Hibernate-managed bean into an action handler you have written, or indeed get out of any tight corners that you frequently find yourself in with webapps when you are trying to get your handlers to figure out what earth they are meant to be operating on...
OK, sorry to go on so long - the basic answer to your question at least is in the middle there
|
 |
|
|
OK, the problem here is that ViewParametersReceiver is generally irrelevant to users, it's internal framework stuff that you shouldn't need to deal with at first (*)
The ViewParameters you're looking for are actually the 2nd argument to Chemtest2Producer - by returning the right type from getViewParameters you guarantee that you can cast these to TopicViewParameters.
I thought for a while about making a "request-scope" version of this "interface" so you could do without the cast (i.e. you could just make a setTopViewParameters(TopicViewParameters viewparams), but in general I'm worrying about the costs of having too many request-scope things these days. I guess given the choice most people would use the cast rather than pay 10 microseconds for a bean...
(*) ViewParamsReceiver is actually used by the main families of ViewProducers (e.g. XML-based and Java-based) to ferry the expected ViewParameter types back and forth)
|
 |
|
|
|
|