f:viewAction does not invoke action method - eclipse

I can't get an action method with the f:viewAction tag to work.
Here's the jsf page:
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<ui:repeat var="genreType" value="#{navigation.genreTypeList}">
<f:metadata>
<f:viewParam name="nameEn" value="#{genreType.name_en}" required="true" />
<f:viewAction action="#{search.searchByGenreType}" />
</f:metadata>
<h:link value="#{genreType.name_de}" outcome="index" includeViewParams="true" /><br />
</ui:repeat>
</ui:composition>
It produces links like this:
[...]/index.jsf;jsessionid=635562E66C7F2FA54504B53D5DAA114C?nameEn=fiction
And here's the bean:
#ManagedBean
#RequestScoped
public class Search implements Serializable {
private static final long serialVersionUID = -5193732222381183093L;
private String nameEn;
public String getNameEn() {
return this.nameEn;
}
public void setNameEn(String nameEn) {
this.nameEn = nameEn;
}
// action methods
public String searchByGenreType() {
System.out.println("searchByGenreType");
return "index";
}
}
I'm using JSF 2.2.5 with Tomcat 7.0.42, IDE is Eclipse Kepler (4.3.1).
I've tried different variations (#PostConstruct in bean, explicit navigation in faces-config.xml, old and new namespaces).
There should be no problem with namespaces since this is fixed since JSF 2.2.5.

This code isn't making any sense. You seem to be confusing <f:viewParam> with <f:param>. You need <f:param> to add HTTP request parameters to links. The <f:viewParam> is to be used to set incoming HTTP request parameters as bean properties.
Given the concrete functional requirement of having a list of links with parameters which in turn should on the target page set the parameter as a bean property and invoke a bean action, here's how you should be implementing it:
The source page with the list of links:
<ui:repeat var="genreType" value="#{navigation.genreTypeList}">
<h:link value="#{genreType.name_de}" outcome="index">
<f:param name="nameEn" value="#{genreType.name_en}" />
</h:link>
<br />
</ui:repeat>
In the target page, apparently index.xhtml, put this somewhere in top, right before <h:head>:
<f:metadata>
<f:viewParam name="nameEn" value="#{search.nameEn}" required="true" />
<f:viewAction action="#{search.searchByGenreType}" />
</f:metadata>
Inside the searchByGenreType() method you can just access that nameEn property directly.
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
When using <ui:composition> templating, where should I declare the <f:metadata>?

Related

Get slingRequest within a bean in CQ 5.6

Including libs/foundation/global.jsp at the top of my jsp winds up calling <cq:defineObjects />, which winds up instantiating the slingRequest or currentNode variables that I can use within my scriptlets. However, I am creating beans and including them like so
<jsp:useBean id="myBean" class="com.foo.bar.MyBean" />
<jsp:setProperty name="myBean" property="request" value="<%= slingRequest %>" />
and in my bean I have a getter/setter
public SlingHttpServletRequest getRequest() {
return resource;
}
public void setRequest(SlingHttpServletRequest request) {
this.resource = resource;
}
Here I'm instantiating the bean and passing in a reference to the current request.
My quesion is, how can I avoid having to pass in this parameter? Is there a way to get a reference to the current request via some sort of static context so that I can set the bean property in the constructor?
There is no way to statically pass the request to newly created bean (and there can't be, as there might be many requests at the same time, so we can't have a shared static variable to store it). You may create a scriptlet:
<% pageContext.setAttribute("myBean", new MyBean(slingRequest)); %>
MyBean property: ${myBean.property}
or get rid of the beans and use one of the frameworks mentioned by Thomas:
Sling Models,
Slice,
NEBA.
You should never pass your request object to Bean classes. I agree with Thomas and Tomek's answer.
But starting to use a framework all of a sudden in the middle of a project to solve this issue is an overkill.
The basic idea here is that the request object should not be passed around. Rather, you should get the resource URI from the request and pass that to your Bean classes.
Additionally you can pass ResourceResolver object to get any resource in your Bean class.
My sample code would look something like this :
<jsp:useBean id="myBean" class="com.foo.bar.MyBean" />
<jsp:setProperty name="myBean" property="resourcePath" value="<%= slingRequest.getResourceURI() %>" />
<jsp:setProperty name="myBean" property="resourceResolver" value="<%= slingRequest.getResourceResolver() %>" />
and my Bean class method would be like this :
public SlingHttpServletRequest getResourcePath() {
return resourcePath;
}
public void setResourceResolver(String resourcePath) {
this.resourcePath = resourcePath;
}
public SlingHttpServletRequest getResourceResolver() {
return resolver;
}
public void setResourceResolver(ResourceResolver resovler) {
this.resolver = resolver;
}
Now in your bean class, you can form the resource object using the resourcePath and ResourceResolver like this :
Resource resource = resourceResolver.resolve(resourcePath);

MvvmCross passing configuration to configurable plugin loader

I am creating a portable MockGeoLocationWatcher that one can substitute in place of the concrete implementations of IMvxGeoLocationWatcher until one has an actual device. This should facilitate development and testing of applications that require geo location.
The PluginLoader class for this plugin currently looks like this:
namespace Pidac.MvvmCross.Plugins.Location
{
public class PluginLoader : IMvxConfigurablePluginLoader
{
private bool _loaded;
public static readonly PluginLoader Instance = new PluginLoader();
public void EnsureLoaded()
{
if (_loaded)
return;
_loaded = true;
var locationWatcher = new MockGeoLocationWatcher();
var data = #"<?xml version='1.0' encoding='utf-8'?>
<WindowsPhoneEmulator xmlns='http://schemas.microsoft.com/WindowsPhoneEmulator/2009/08/SensorData'>
<SensorData>
<Header version='1' />
<GpsData latitude='48.619934106826' longitude='-84.5247359841114' />
<GpsData latitude='48.6852544862377' longitude='-83.9864059059864' />
<GpsData latitude='48.8445703681025' longitude='-83.7337203591114' />
<GpsData latitude='48.8662561090809' longitude='-83.2393355934864' />
<GpsData latitude='49.0825970371386' longitude='-83.0415816872364' />
<GpsData latitude='49.2621642999055' longitude='-82.7229781716114' />
<GpsData latitude='49.2621642999055' longitude='-82.6021285622364' />
<GpsData latitude='49.2047736379815' longitude='-82.3054977028614' />
</SensorData>
</WindowsPhoneEmulator>";
locationWatcher.SensorLocationData = data;
Mvx.RegisterSingleton(typeof(IMvxGeoLocationWatcher), locationWatcher);
}
public void Configure(IMvxPluginConfiguration configuration)
{
}
}
public class MockLocationWatcherConfiguration : IMvxPluginConfiguration
{
public static readonly MockLocationWatcherConfiguration Default = new MockLocationWatcherConfiguration();
// ideally, we should use this property to point to a file or string containing location data
// this should be configurable outside of code base.
public string SensorLocationData { get; set; }
}
}
I will like to pass the sensor data, currently hardcoded into the variable called "data" through an instance of MockLocationWatcherConfiguration but do not know where the MvvmCross framework is expecting to load the configuration for this plugin before IMvxConfigurablePluginLoader.Configure(configuration) is invoked. Ideally, I should specify this through configuration.
I looked at the Json plugin's implementation of PluginLoaded but still could not figure out where the configuration was retrieved before a cast was attempted in IMvxConfigurablePluginLoader.Configure.
Any ideas or pointers will be greatly appreciated.
TIA.
This is covered in the draft wiki page https://github.com/slodge/MvvmCross/wiki/MvvmCross-plugins - see "writing a configurable plugin"

What's the Struts 2 equivalent of ASP.NET's Request.Form (or FormCollection)?

I'm dynamically adding textboxes to a form on my jsp page using Javascript. When that form is submitted to an action, how does my action get the values of those textboxes? (I'm using Struts 2, btw.) In ASP.NET, I was able to find them in Form.Request/FormCollection. Is there a Struts 2 equivalent? Thanks a million.
In Struts2, you create beans in the form to do submit values. In order to create the input text-box, use the <s> tag. For example :
<s:textfield name="loginBean.userName" label="UserName" required="true" />
Here loginBean is the bean passed to the jsp page when.
Bean consists of variable declarations and getters-setters for the variable.
Then in the back-end Java where the form is submitted to, you can access the same bean.
Declare getter-setter in Java and then you can access the properties of the bean.
public LoginBean getLoginBean() {
return loginBean;
}
public void setLoginBean(LoginBean loginBean) {
this.loginBean = loginBean;
}
public String authenticate() {
String username = loginBean.getUserName();
I would recommend looking at source codes of open-source Struts projects.
It sounds like you're trying to populate a dynamic list. To do that, you just have to use the [n] index syntax at the end of your Action class property name:
HTML:
<input type="text" name="yourCollection[0]" value="first value" />
<input type="text" name="yourCollection[1]" value="second value" />
<input type="text" name="yourCollection[2]" value="third value" />
Action Class:
public class YourAction extends Action {
public List<String> yourCollection;
public List<String> getYourCollection(){
return yourCollection;
}
public void setYourCollection(List<String> aCollection){
this.yourCollection = aCollection;
}
}

Can't get JSF input field value on JAVA backend

I have following UI part on JSF - it's simple search form with input field and submit:
<h:form>
<h:commandButton action="#{operation.found}" value="#{msg.search}" />
<h:inputText name="searchParam"/>
</h:form>
And correspondingly, on backend, i attempt to get value of input field next way:
public List<Store> getFound() {
String name = (String) FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap().get(
"searchParam");
SessionFactory sessionFactory = new Configuration().configure()
.buildSessionFactory();
HibernateTemplate hbt = new HibernateTemplate();
hbt.setSessionFactory(sessionFactory);
foundStores = hbt.find(BEAN_PATH + " WHERE name = ?",
new Object[] { name });
return foundStores;
}
And null name is passed to backend.
It seems that problem in .jsf part, but from first glance looks ok...
You must point the <h:inputText> to a managed-bean property:
<h:inputText name="searchParam" value="#{searchBean.searchParam}" />
and define in your bean:
private String searchParam;
public String getSearchParam() {..}
public void setSearchParam(String searchParam) {..}
and then use the searchParam in your getFound() method;
Of course, you need to have the bean defined as managed bean, but I assume you have done it:
<managed-bean>
<managed-bean-name>searchBean</managed-bean-name>
<managed-bean-class>mypackage.SearchBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
You can check a JSF tutorial (like this, for example)

Updating Bean from JSF dataTable

I've got this h:dataTable and form:
<h:form>
<h:dataTable value='#{bean.allData.dataItems}' var='item'>
<h:column>
<h:outputText value='#{item.id}' />
</h:column>
<h:column>
<h:inputText value='#{item.name}' />
</h:column>
</h:dataTable>
<h:commandButton value="Save" action="#{bean.saveEntries}"/>
</h:form>
So the table shows the id and a textbox with the name in. That works. When a user clicks the button, I'd like it to save any changes to the name field.
DataBean has:
private Vector<ItemBean> dataItems;
// constructor here
public void setDataItems(Vector v) {
dataItems = v;
}
public Vector getDataItems() {
return dataItems;
}
and ItemBean has...
private String id;
private String name;
// setter for both
// getter for both
Bean has a variable 'allData' of type 'DataBean'.
Bean also has a method saveEntries() which is currently blank (as I'm not sure how it works). How do I reference the inputs to set these values?
JSF has already done it during UPDATE MODEL VALUES phase. Print/debug the local variables and you'll see. All you need to do in the save method is just persisting the data in some datastore.
Also see the following articles for more background information and examples:
Using datatables.
Debug JSF lifecycle.