Ionut
Ionut

Reputation: 2858

JSF navigation parameter dependency

I'm trying to implement this simple example in JSF: There is a user.xhtml page which can be accessed with an id parameter (user.xhtml?id=3 / user.xhtml?id=12). Depending on the id The page should display the info of the user who has that specified id.

@ManagedBean
@RequestScoped
public class OverviewController extends BaseController{

private UserDetails details;

@PostConstruct
@SuppressWarnings("unused")
private void init(){
    Integer userId = getIntegerParam(Constants.PARAMETER_USER); //this brings the value of the user parameter as an Integer
    if (userId != null){
        UserService userService = new UserService();
        details = userService .getDetails(userId);
    }
}

//GET & SET

}

In the xhtml file I have the followings:

<div>
    Name: #{overviewController.details.name}
    City: #{overviewController.details.city}
</div>

The link which guided the control here:

<h:link outcome = "user.xhtml" value = "details">
    <f:param name = "user" value = "2">
</h:link>

I was under the impression that when accessing the overviewController via EL the ManagedBean will get Constructed and in the @PostConstruct the details would get initialised. But I get no results and the overviewController isn't even constructed. I'm going further with my question and I ask how can a search depending on multiple parameters or a sort can be implemented?

Upvotes: 0

Views: 2959

Answers (2)

BalusC
BalusC

Reputation: 1108742

As to your concrete problem, your @PostConstruct is incorrectly been declared private instead of public.

As to your concrete functional requirement, this is not entirely the right way. You need a <f:viewParam> in the target page to set the user ID request parameter as an UserDetails property in the backing bean.

user.xhtml

<f:metadata>
    <f:viewParam id="param_id" name="id" value="#{overviewController.details}"
        converter="userDetailsConverter" converterMessage="Bad request, unknown user"
        required="true" requiredMessage="Bad request, use a link from within the system"
    />
</f:metadata>
<h:message for="param_id" />

UserDetailsConverter

@FacesConverter("userDetailsConverter")
public class UserDetailsConverter implements Converter {

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (!(value instanceof UserDetails) || ((UserDetails) value).getId() == null) {
            return null;
        }

        return String.valueOf(((UserDetails) value).getId());
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null || !value.matches("\\d+")) {
            return null;
        }

        UserDetails details = new UserService().getDetails(Integer.valueOf(value));

        if (details == null) {
            throw new ConverterException(new FacesMessage("Unknown user ID: " + value));
        }

        return details;
    }

}

OverviewController

private UserDetails details; // Getter+setter

See also:

Upvotes: 1

Natix
Natix

Reputation: 14257

Well, I don't know how your method getIntegerParam actually works, but I usually implement processing query parameters like this.

Edit: I'm not actually sure if the init() would be really invoked after the userId property is set (I usually invoked it directly from the setter), but it probably should as @PostConstruct methods are invoked after dependencies are injected.

@ManagedBean
@RequestScoped
public class OverviewController extends BaseController {

    @ManagedProperty("#{param['userId']}")
    private String userId; // not sure if can automatically be parsed to Integer

    private UserDetails details;

    @PostConstruct
    private void init() {
        if (userId != null){
            UserService userService = new UserService();
            details = userService .getDetails(userId);
        }
    }

    // getter & setter for userId
}

Upvotes: 0

Related Questions