antarkt1s
antarkt1s

Reputation: 135

Automatically set value of a managed bean variable with JSF

I would like to pass an value to a managed bean under the hood. So I have this managed bean:

@ManagedBean(name = "mbWorkOrderController")
@SessionScoped
public class WorkOrderController {

    // more attributes...

    private WorkOrder workOrderCurrent;

    // more code here...

    public WorkOrder getWorkOrderCurrent() {
        return workOrderCurrent;
    }

    public void setWorkOrderCurrent(WorkOrder workOrderCurrent) {
        this.workOrderCurrent = workOrderCurrent;
    }
}

It holds a parameter workOrderCurrent of the custom type WorkOrder. The class WorkOrder has an attribute applicant of type String.

At the moment I am using a placeholder inside my inputtext to show the user, what he needs to type inside an inputText.

<p:inputText id="applicant"
    value="#{mbWorkOrderController.workOrderCurrent.applicant}"
    required="true" maxlength="6"
    placeholder="#{mbUserController.userLoggedIn.username}" />

What I want to do, is to automatically pass the value of mbUserController.userLoggedIn.username to mbWorkOrderController.workOrderCurrent.applicant and remove the inputText for applicant completely from my form.

I tried to use c:set:

<c:set value="#{mbUserController.userLoggedIn.username}" target="#{mbWorkOrderController}" property="workOrderCurrent.applicant" />

But unfortunatelly I get a javax.servlet.ServletException with the message:

The class 'WorkOrderController' does not have the property 'workOrderCurrent.applicant'.

Does anybody have an advice?

Upvotes: 1

Views: 8827

Answers (2)

Mart&#237;n Straus
Mart&#237;n Straus

Reputation: 568

Perhaps you could explain the context a bit more, but here's another solution. If you're navigating from another page, you can pass some identifier of work WorkOrder in the URL, like this http://host:port/context/page.xhtml?workOrderId=1.

Then, you can set the identifier in the managed bean like this:

<h:html>
    <f:viewParam name="workOrderId" value="#{mbWorkOrderController.id}"/>
</h:html>

You'll have to add a new property to your bean:

public class WorkOrderController {
    private long id;
    public long getId() { return id; }
    public void setId(long id) { this.id = id; }

    // ...
}

And then, after the property has been set by JSF, you can find the work order in a lifecycle event:

<h:html>
    <f:viewParam name="workOrderId" value="#{mbWorkOrderController.id}"/>
    <f:event type="preRenderView" listener="#{mbWorkOrderController.findWorkOrder()}"/>
</h:html>

public class WorkOrderController {
    private long id;
    public long getId() { return id; }
    public void setId(long id) { this.id = id; }

    public void findWorkOrder() {
        this.workOrderCurrent = null /* some way of finding the work order */
    }

    // ...
}

This strategy has the advantage of letting you have bookmarkable URLs.

Upvotes: 0

BalusC
BalusC

Reputation: 1108722

The class 'WorkOrderController' does not have the property 'workOrderCurrent.applicant'.

Your <c:set> syntax is incorrect.

<c:set value="#{mbUserController.userLoggedIn.username}"
       target="#{mbWorkOrderController}" 
       property="workOrderCurrent.applicant" />

You seem to be thinking that the part..

value="#{mbWorkOrderController.workOrderCurrent.applicant}"

..works under the covers as below:

WorkOrderCurrent workOrderCurrent = mbWorkOrderController.getWorkOrderCurrent();
workOrderCurrent.setApplicant(applicant);
mbWorkOrderController.setWorkOrderCurrent(workOrderCurrent);

This isn't true. It works under the covers as below:

mbWorkOrderController.getWorkOrderCurrent().setApplicant(applicant);

The correct <c:set> syntax is therefore as below:

<c:set value="#{mbUserController.userLoggedIn.username}"
       target="#{mbWorkOrderController.workOrderCurrent}" 
       property="applicant" />

That said, all of this isn't the correct solution to the concrete problem you actually tried to solve. You should perform model prepopulating in the model itself. This can be achieved by using @ManagedProperty to reference another bean property and by using @PostConstruct to perform initialization based on it.

@ManagedBean(name = "mbWorkOrderController")
@SessionScoped
public class WorkOrderController {

    @ManagedProperty("#{mbUserController.userLoggedIn}")
    private User userLoggedIn;

    @PostConstruct
    public void init() {
        workOrderCurrent.setApplicant(userLoggedIn.getUsername());
    }

    // ...
}

Upvotes: 4

Related Questions