Working on a large Web app, I have houndresds of JSPs.
Each JSP includes (ONLY) a set of internal tags, for instance:
<AAA:INPUT value="bbb" state="<%=getPageState()"/>
This tag is rendered into an HTML input field, with a readonly/enabled state, based on the return value from getPageState().
This basically allows me to set the complete page as enabled/disabled from a single entry point.
I don't like this (mainly because it drives me away from writing the HTML I want and I need to maintain attributes for each HTML attribute I want), I know I can something similar on client side with JavaScript.
Are there other approachs to control the state of a complete JSP form in a single point on the web-server side?
The way I would go about this would be to convert the getPageState() method into a tag, and then use this tag within your custom tags. That way, you don't need to explicitly pass in the page-state on every invocation of your custom tag.
Of course, this means that you would have to modify all your custom tags to use this new tag, but I think that's better than having your code littered with explicit calls to get the page state. Not to mention, an opening for inconsistencies if a developer forgot to check the page state.
Also, now the decision as to how the element needs to be rendered rests in the custom tag itself (where it belongs).
The only problem I see is that now you have to make multiple (redundant) calls per element to get the page state, which is not that efficient. To get around this problem, you can have your custom tag (that gets the page state) set a page attribute, and have your custom tags inspect this page attribute to decide if the form element should be disabled or not (another way would be to create a variable with the scope AT_END).
Related
I am currently learning JSF and was rather amazed and puzzled when I realized that whenever we use <h:form>, the standard behavior of JSF is to always show me the URL of the previous page in the browser, as opposed to the URL of the current page.
I understand that this has to do with the way JSF always posts a form to the same page and then just renders whatever page the controller gives it back to the browser which doesn't know the page location has changed.
It seems like JSF has been around for long enough that there must be a clean, solid way to deal with this. If so, would you mind sharing?
I have found various workarounds, but sadly nothing that seems like a real solid solution.
Simply accept that the URL is misleading.
Append "?faces-redirect=true" to the return value of every bean's action and then
figure out how to replace #RequestScoped with something else (Flash Scopes, CDI conversation, #SessionScoped, ...).
accept to have two HTTP round trips for every user action.
Use some method (e.g. 3rd party library or custom code) to hide the page name in the URL, always using the same generic URL for every page.
If "?faces-redirect=true" is as good as it gets, is there a way do configure an entire application to treat all requests this way?
Indeed, JSF as being a form based application targeted MVC framework submits the POST form to the very same URL as where the page with the <h:form> is been requested form. You can confirm it by looking at the <form action> URL of the generated HTML output. This is in web development terms characterized as postback. A navigation on a postback does by default not cause a new request to the new URL, but instead loads the target page as content of the response. This is indeed confusing when you merely want page-to-page navigation.
Generally, the right approach as to navigation/redirection depends on the business requirements and the idempotence (read: "bookmarkability") of the request (note: for concrete code examples, see the "See also" links below).
If the request is idempotent, just use a GET form/link instead of POST form (i.e. use <a>, <form>, <h:link> or <h:button> instead of <h:form> and <h:commandXxx>).
For example, page-to-page navigation, Google-like search form, etc.
If the request is non-idempotent, just show results conditionally in the same view (i.e. return null or void from action method and make use of e.g. <h:message(s)> and/or rendered).
For example, in-page data entry/edit, multi-step wizard, modal dialog, confirmation form, etc.
If the request is non-idempotent, but the target page is idempotent, just send a redirect after POST (i.e. return outcome with ?faces-redirect=true from action method, or manually invoke ExternalContext#redirect(), or put <redirect/> in legacy XML navigation case).
For example, showing list of all data after successful editing, redirect after login, etc.
Note that pure page-to-page navigation is usually idempotent and this is where many JSF starters fail by abusing command links/buttons for that and then complain afterwards that URLs don't change. Also note that navigation cases are very rarely used in real world applications which are developed with respect to SEO/UX and this is where many JSF tutorials fail by letting the readers believe otherwise.
Also note that using POST is absolutely not "more secure" than GET because the request parameters aren't immediately visible in URL. They are still visible in HTTP request body and still manipulatable. So there's absolutely no reason to prefer POST for idempotent requests for the sake of "security". The real security is in using HTTPS instead of HTTP and checking in business service methods if currently logged-in user is allowed to query entity X, or to manipulate entity X, etc. A decent security framework offers annotations for this.
See also:
What is the difference between redirect and navigation/forward and when to use what?
JSF implicit vs. explicit navigation
What URL to use to link / navigate to other JSF pages
Bookmarkability via View Parameters feature
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
When should I use h:outputLink instead of h:commandLink?
Creating master-detail pages for entities, how to link them and which bean scope to choose
Retaining GET request query string parameters on JSF form submit
Pass an object between #ViewScoped beans without using GET params
I have a project which gives the user interface to create the Dynamic forms on the fly.
User can select different fields like textbox, textarea, date etc and create a model for the same.
Once the user chooses the component and creates a form, then we need to show that form at a specifies place. The form components are rendered through common jsp page which accepts pojo object and then distributes that object to our own custom created tags for input,checkbox,radio,date etc.
Issue is it takes very 10-15 seconds to render the form.
Is there a way i can create templates or say html code of created forms and store them in DB and render through them. (Provided i am able to still bind data using Spring MVC, show dropdown values, selected or saved data in the fields.)
You may want to take a look at Metawidget. It renders different forms inside a common JSP as you describe, and does not have the 10-15 second issue you are seeing.
Metawidget is Open Source, so you can examine how it works, or even use it 'as is' (it is designed to be embedded inside projects such as yours). There's a good example tutorial here: http://metawidget.org/doc/reference/en/html/ch01s03.html#section-introduction-part2-web
Better way is to create you own custom tags and remove repeated code.
This will decrease the compilation time and further decreases the loading time of the page.
In Stuts2 I am using Tiles plugin to create a layout for the website (menu, footer, header etc.) that is consistent on every page.
Now each tile is just a static HTML content.
Is it possible to make a Tile more dynamic by eg. calling a Footer action class every time the footer is to be rendered? For example: to fetch footer content from database.
If I was to do that inside every page's action class in my application this would make for a very unusable code...
So maybe it is possible from Tile perspective?
There is only one way to do what you ask with a tiles version less than 2.2.2 and that is with a "preparer".
This however is not an integration with struts2 but would mean the preparer it self will access the service layer to get the required content for the view and all that content would need to be set though tiles attributes.
With tiles versions 2.2.2 and higher:
You can use OGNL expressions within tiles attributes, this can allow access to some struts2 interaction as well as static method access. With static method access you can call a method to return a string how ever you want. Creating such a string would be on par with writing a scriptlet.
To upgrade you need to either manually override some jars to get tiles 2.2.2, or to get version three you will need to implement your own result type: How to integrate Struts 2 with Tiles 3.
I don't actually recommend either of the above methods at this time, tiles 3 is recommended but not as an excuse to do something as bad as writing a scriptlet. It would probably be better to use the s:action tag in a tile, as mentioned by David or use an Ajax method as mentioned by Jaiwo99. The reason being that both these methods keep with struts2 while the ones I presented would be unusual and be harder to maintain. Personally I would lean towards the ajax methods.
Struts2 along with the struts2-json-plugin makes creating json services very simple. Tiles is a nice system for reducing boiler plate. If ajax is used heavily the two really can compliment each other. You can make a lot of reusable ajax components, just be sure to not hard code the urls of actions. Always use the s:url tag and assign that to JS variables.
Try following code:
$('#footer').load('your/action/with/namespace');
i'm assuming your footer is with id footer, everytime you open a page, your footer action class will be called and the data can be fetched dynamically.
Is there a way to call ids that are created in html page without specifically giving wicket:id in the component. If so, how can I do that?
What I am trying to accomplish is to get access of the component to assign a default value from CMS. I could assign the default value using JS, however I need that value to be populated to Java so that I could use that in my class to update my business logic depending on the defaulted value.
As I understand it, Wicket is component oriented which means that single component (piece of HTML code) can't see all the HTML. And my guess is that at some late stage, you want to look at the whole page HTML and do something with a DOM node with a specific ID.
I'm not sure what the correct solution should be. One way is to put the value into the user's session, so it's available for each component and your business logic.
In many cases you want to add HTML-Controls or Facelets to your Website, but how easy is it really to just access these when you call upon an action?
I have the following commandLink to execute an Action
<h:commandLink action="#{MyBean.save}" value="">
<f:verbatim><input type="button" value="Save"/></f:verbatim>
<f:param name="id" value="#{MyBean.id}"/>
</h:commandLink>
The Param is there to save the QueryString-state so my application won't crash.
Now, imagine you have a <input type="text" /> or <h:inputText value="hello" /> now these components are fundamental to get your site up and running, especially if you are creating some dynamics.
However, if the Controls are not Bound to anything, or if you have a Listbox which you can add elements to with JavaScript, how do you access these when you execute the commandLink or commandButton? Do you Have to bind the controls to your Bean or is it possible to access this FaceContext in another way to retreive the values of either a listbox, input text or whatever else you would want to have?
It can be difficult to treat a JSF-rendered page as a big glob of HTML and JavaScript (which, I think, is at the heart of the question). You cannot add arbitrary form controls to the application on the client and expect the JSF framework to interpret them. JSF uses pre-defined components, so a component would have to know how to interpret the extra data coming from the request. Because it all ends up as a HTML form interpreted by a servlet, the data sent from the client will still end up in the parameter map - but, these values won't pass through the JSF lifecycle, so won't benefit from validation/data binding/etc.
A JSF control tree looks much like any other widget tree (like Swing or SWT):
UIViewRoot
|_HtmlForm
|_HtmlInputText
|_HtmlCommandButton
A JSF control basically works like this:
a UIComponent instance encapsulates the values (initially populated from the JSP/Facelet); example: HtmlInputTextarea
When the page is rendered, the lifecycle looks up the Renderer implementation for the component; the Renderer writes markup to the output
When the form is posted, the same renderer looks at the incoming parameter map for keyed values it recognises and will eventually (after conversion and validation) push the new value into the UIComponent (which may in turn push it to a value binding for the model)
Taking your specific example of a listbox - this is a tricky one. JSF provides a HtmlSelectManyListbox which ends up as a SELECT element in HTML. It is possible to add OPTION children to the DOM using JavaScript on the client, but this doesn't do any good when it comes to submitting the form. If you read the HTML spec, it says:
Only selected options will be successful. When no options are selected, the control is not successful and neither the name nor any values are submitted to the server when the form is submitted.
So, when the form is submitted, only the list elements that are selected by the user would be transmitted to the server. You would need some hidden fields to get all the new data to the server. There isn't a control in the core set that will help you with this.
You have a few options:
Find an existing control from a 3rd party library that does this. If you can't find one, consider using AJAX to perform the updates - look at the RichFaces select controls for inspiration.
Write your own control (warning: read the spec and be aware of the many fiddly, manual steps)
Put up with having to perform a POST operation every time you want to add an element to the list
You can retrieve values from "non-JSF" controls on your page using the standard request parameter map that can be accessed with
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()
in whatever action you call eg. MyBean.save()