I have built a custom control which renders an arraylist of java objects via a repeat control. Via the property definition I can provide which fields from the underlying java object I want to display. In the back-end I read this value e.g. via
obj[compositeData.columnField1]
This works well with static data, but sometimes I want to format the before rendering e.g. when the field contains a notesname and I only want to display the commonname.
I am wondering how I could set up something like that.
Now I am only passing the field name, which will be picked up by the cc to read the value.
E.g. for the jQuery DataTables plugin you can define a render function for a column and use the data variable of that column within that render function (e.g. build an anchor link or button in that column).
Can I provide something similar for SSJS e.g. I pass the render function as text (or object?) and in the back-end it will be transformed to ssjs.
Functions in JavaScript are first class citizens on objects. Presume you created a JS object with all the rendering functions and stored it in one of the scopes. E.g. viewScope.renderFunctions. Then hand over the name of the render function and inside use something like:
var renderfunc = viewScope.renderFunctions[funcname];
var result = renderfunc(rawdata);
return result;
That should do the trick
I found an answer here on stackoverflow. The eventhandler for my button looks as followed:
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="pnlContainer"
action="#{javascript:if (compositeData.actionButton.action) if (!compositeData.actionButton.action.call()) return;}">
</xp:eventHandler>
For my custom control I have set up a property:
<property>
<property-name>action</property-name>
<property-class>javax.faces.el.MethodBinding</property-class>
<property-extension>
<designer-extension>
<editor>com.ibm.workplace.designer.ide.xfaces.internal.editors.MethodBindingEditor</editor>
</designer-extension>
</property-extension>
<description>ssjs that action button must perform</description>
</property>
Make sure the class and editor are as above.
Then the property on the xpage containing the custom control contains the ssjs:
action="#{javascript:removeSelected}"
This is a function that resides in a SSJS script library. The key here is not to provide ANY parameters of parantheses (!!!)
The SSJS function is as followed:
function removeSelected(){
var accessList = sessionScope.get("removalList");
var nsf_committee = datasources["COM1_DB_FILEPATH"];
var db:NotesDatabase = session.getDatabase(session.getServerName(), nsf_committee);
for (var i = 0; i < accessList.length; i++) {
var doc:NotesDocument = db.getDocumentByUNID(accessList[i]);
if (null != doc){
doc.remove(true);
accessList.remove(accessList[i]);
}
}
}
(here I remove documents from the database. the unid id's reside in a an arraylist. the array list is set via a checkbox group for each row in my repeat control.)
Considering you would likely want to re-use the component in many contexts of your app I would approach the problem with an helper class and interface
public class FieldManager {
public static interface FieldDetail {
String getName();
void getAction();
}
private List<FieldDetail> fieldDetails = new List<FieldDetail>();
public FieldManager() {
}
public FieldManager(List<FieldDetail> fieldDetails) {
this.fieldDetails.addAll(fieldDetails);
}
public void addFieldDetail(FieldDetail fieldDetail) {
this.fieldDetails.add(fieldDetail);
}
public List<FieldDetail> getFieldDetails() {
return fieldDetails;
}
}
With this succinct definition you could now be able to implement the FieldDetail interface with a generic class or alternative specialized classes.
Then in the custom control you set a property as value or whatever, the <property-class> tag will be FieldManager and in the custom control you would know how everything plays out because the class FieldManager and the FieldDetail are the contract for you.
<xp:repeat disableOutputTag="true"
value="#{compositeData.value.fieldDetails}" var="fieldDetail">
<xp:link text="#{fieldDetail.name}">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="pnlContainer"
action="#{fieldDetail.action}">
</xp:eventHandler>
</xp:link>
</xp:repeat>
Or whatever your code might be. Anyway, that's the gist of it.
Related
I am working on a PDF Invoice generator in Vaadin 7. The code as it stands at the time of this writing can be found here. The repo includes a crude class diagram.
My question concerns the best practice of collecting the user input from the TextField and other Vaadin components to create an instance of Invoice.
Currently it works like this:
When the user clicks the button to generate the pdf, the class VaadinInvoiceGui (a Panel) calls the method createPdf(VaadinInvoiceGui gui) in the class VaadinInvoiceController.
VaadinInvoiceController calls method getInvoiceFromForm(VaadinInvoiceGui gui) in class InvoiceMapperImpl.
InvoiceMapperIml creates and returns an Invoice (POJO) by calling get methods in the VaadinInvoiceGui that gets passed to it. These getters return the values of the components in the view.
VaadinInvoiceController takes the Invoice returned by InvoiceMapperImpl and goes on to create pdf from it etc..
The getters in VaadinInvoiceGui look like this.
public String getCustomerName() {
return infoPanel.getCustomerNameTextField().getValue().toString();
}
public String getCustomerStreet() {
return infoPanel.getCustomerStreetTextField().getValue().toString();
}
public String getCustomerCity() {
return infoPanel.getCustomerCityTextField().getValue().toString();
}
...
I really don't feel like it's a good idea to pass the whole gui class to the controller and especially to the mapper, but I'm not sure what would be a better way of doing it. I could change the method createPdf(VaadinInvoiceGui gui) to something like createPdf(String customer name, String customerStreet, ...) but the number of parameters of the method would grow huge. I could do it using setters but then it would basically be doing the object mapping in the gui which doesn't seem like a very clean idea either.
What is the proper way of doing this?
Write a bean for the data to pass around as your model. Then use the FieldGroup to bind between model and form. Wrap the model as BeanItem<Model>. Binding is either done by name (convention) or by annotation #PropertyId.
master-detail-example: https://vaadin.com/wiki/-/wiki/Main/Creating+a+master-details+view+for+editing+persons
general infos: https://vaadin.com/book/vaadin7/-/page/datamodel.html
binding in forms: https://vaadin.com/book/vaadin7/-/page/datamodel.itembinding.html
I would like to know if and how it is possible working on SmartGWT to change the class associated to an element at runtime.
Take for example the underlying code that renders contents inside a div, I would like to know if and how I can modify at runtime the css class associated to the div.
HTMLFlow productInfo = new HTMLFlow(productInfoHtml);
productInfo.setStyleName("loginProductInfo");
productInfo.setHeight(13);
productInfo.setMargin(5);
Note: I'm using Smart GWT version 4.0
I have not used SmartGWT, but if HTMLFlow is a widget you can use GQuery for changing classes on fly, or css' rules.
Something like:
if (something) {
GQuery.$(productInfo).css("width", "70px");
else{
GQuery.$(productInfo).css("width", "30px");
}
About the css classes:
if (something) {
GQuery.$(loginProductInfo).removeClass("loginProductInfo");
} else {
GQuery.$(loginProductInfo).addClass("secondLoginProductInfoCss");
}
In fact, the solution is simpler than I had thought.
It is sufficient to keep a reference to the object of which you want to change the css class, then invoke again the method setStyleName.
Keep a reference to the widget (in our case productInfo) as a field of the original class, then change the css assignment when necessary.
So in the end the object productInfo becomes a field in the main class and then we can change the css assignment simply by invoking again the method setStyleName passing the new css class.
The object productInfo becomes a field in the main class
protected HTMLFlow productInfo = new HTMLFlow();
The code of the question example is modified as in the snippet
productInfo.setContents(productInfoHtml);
productInfo.setStyleName("login-product-info");
productInfo.setHeight(16);
productInfo.setWidth100();
Now I can change the css class assigned to the widget productInfo when the event onMouseOver occurs on the object forgot.
forgot.addMouseOverHandler(new MouseOverHandler() {
#Override
public void onMouseOver(MouseOverEvent event) {
productInfo.setStyleName("my-new-style");
}
});
I've got in my .tml file something like this:
<t:beaneditform t:id="adForm" object="editableAd"
reorder="actiontype,shops,movies,streams,widgets" ....
My question is how to access (refer) actionType, which is an Enum (and in fact SELECT) in .java file? I just need to handle event when user changes the value of this select (dropdown), obviously before submitting the form itself.
If something like this would work for me...
#OnEvent(component = "adForm.actionType", value=EventConstants.VALUE_CHANGED)
public void actionTypeValueChanged(String value) {
log.info("value is: " + value);
}
To be updated with the changed value in a Select html component on the client side, have a tapestry select component in your template file with a t:zone attribute (i.e. in your case it could point to any dummy zone, this is only needed to be set correctly if you need to update a zone when a value is changed)
Also set the t:value attribute to your enum variable in your page\component java file, usually this variable will be annotated with tapestry's #Property.
Example:
<t:select t:id="myEnumVariable" t:zone="dummyZone" t:value="myEnumVariable"/>
myEnumVariable is used to refer to your class's variable AND to act as an ID (i.e. the actual string myEnumVariable is used as an id), this is not necessary, but it's more readable and maintainable that way)
public class MyClass{
#Property
private MyEnum myEnumVariable;
#OnEvent(component = "myEnumVariable", value=EventConstants.VALUE_CHANGED)
public void actionTypeValueChanged(**MyEnum** newValue) {
this.myEnumVariable = newValue; // <<<<<<
log.info("value is: " + myEnumVariable );
}
}
If you don't mind using the ChenilleKit framework for tapestry you could try using the
framework's OnEvent mixin.
You 'll find the example on the link I share but basically you add two attributes the select tag:
<t:select t:id="myselect" ... t:mixins="ck/OnEvent" t:event="change" />
then you add the event handler on your java class:
#OnEvent(component="myselect", value='change')
public void onChangeDoSomething(String value) {
hope that helps, by the way I think Muhammad's answer is equally correct (and doesn't requires the use of an extra framework).
I have been wrestling with this problem for a while. I would like to use the same Stripes ActionBean for show and update actions. However, I have not been able to figure out how to do this in a clean way that allows reliable binding, validation, and verification of object ownership by the current user.
For example, lets say our action bean takes a postingId. The posting belongs to a user, which is logged in. We might have something like this:
#UrlBinding("/posting/{postingId}")
#RolesAllowed({ "USER" })
public class PostingActionBean extends BaseActionBean
Now, for the show action, we could define:
private int postingId; // assume the parameter in #UrlBinding above was renamed
private Posting posting;
And now use #After(stages = LifecycleStage.BindingAndValidation) to fetch the Posting. Our #After function can verify that the currently logged in user owns the posting. We must use #After, not #Before, because the postingId won't have been bound to the parameter before hand.
However, for an update function, you want to bind the Posting object to the Posting variable using #Before, not #After, so that the returned form entries get applied on top of the existing Posting object, instead of onto an empty stub.
A custom TypeConverter<T> would work well here, but because the session isn't available from the TypeConverter interface, its difficult to validate ownership of the object during binding.
The only solution I can see is to use two separate action beans, one for show, and one for update. If you do this however, the <stripes:form> tag and its downstream tags won't correctly populate the values of the form, because the beanclass or action tags must map back to the same ActionBean.
As far as I can see, the Stripes model only holds together when manipulating simple (none POJO) parameters. In any other case, you seem to run into a catch-22 of binding your object from your data store and overwriting it with updates sent from the client.
I've got to be missing something. What is the best practice from experienced Stripes users?
In my opinion, authorisation is orthogonal to object hydration. By this, I mean that you should separate the concerns of object hydration (in this case, using a postingId and turning it into a Posting) away from determining whether a user has authorisation to perform operations on that object (like show, update, delete, etc.,).
For object hydration, I use a TypeConverter<T>, and I hydrate the object without regard to the session user. Then inside my ActionBean I have a guard around the setter, thus...
public void setPosting(Posting posting) {
if (accessible(posting)) this.posting = posting;
}
where accessible(posting) looks something like this...
private boolean accessible(Posting posting) {
return authorisationChecker.isAuthorised(whoAmI(), posting);
}
Then your show() event method would look like this...
public Resolution show() {
if (posting == null) return NOT_FOUND;
return new ForwardResolution("/WEB-INF/jsp/posting.jsp");
}
Separately, when I use Stripes I often have multiple events (like "show", or "update") within the same Stripes ActionBean. For me it makes sense to group operations (verbs) around a related noun.
Using clean URLs, your ActionBean annotations would look like this...
#UrlBinding("/posting/{$event}/{posting}")
#RolesAllowed({ "USER" })
public class PostingActionBean extends BaseActionBean
...where {$event} is the name of your event method (i.e. "show" or "update"). Note that I am using {posting}, and not {postingId}.
For completeness, here is what your update() event method might look like...
public Resolution update() {
if (posting == null) throw new UnauthorisedAccessException();
postingService.saveOrUpdate(posting);
message("posting.save.confirmation");
return new RedirectResolution(PostingsAction.class);
}
Is there's a way to get the value returned by a java controller method in javascript in the views ?
what I want to do is:
i'm in view showX rendered by controller method X.show()
i want to create an object y so $.post('#{Y.create()}')
now i need the id of the created object of type y to use it in the same view (showX).
is that possible?
It sound like what you need (although your question is very vague), is to return JSON from your controller method.
Such as, in your controller, you can do
public static void myActionOne() {
renderJSON(myObject);
}
And then you will call myActionOne from your javascript using $.post. I would also suggest looking at the Play jsAction tag if you are not already using it. This will return a JSON representation of the object. You can then take whatever information you need and call a second action in the same way.
Again, in the second action, I would suggest jsAction, as it makes passing parameters into your actions far easier.
EDIT:
Based on your edit, then all you need to do is in your controller method Y.create, do something like
public static void create() {
MyObject obj = new MyObject();
obj.save();
Long id = obj.id;
renderJSON(id);
}
Obviously your code to create your object will be different, but you get the idea. You can then just take the data from the JQuery post response, and access the id that has been returned, using standard javascript.
You question is too vague. But you probably will need of AJAX to get a value of this kind.
Take a look here: http://www.oracle.com/technetwork/articles/javaee/ajax-135201.html