0

I want to build a custom component in JSF that could :

  1. retrieve a value from its value attribute
  2. display this value
  3. be able to update this value through Javascript (will update bean attribute used in value component attribute)
<t:myComponent value="#{myBean.value}" />

will display

<div>
    <input id="my_input" type="text" value="my_value" />
    <button onclick="update_value(document.getElementById('my_input').value)">update</button>
</div>

<script>
    function update_value(val) {
        // ???
    }
</script>

and when we click the button, it will change myBean.value by the current content of the input (that user can change obviously).

As I understand, it looks easy to display the value in the component with the ResponseWriter but I do not understand how to build Javascript to call the component to change the value of the component.

example

// myBean.value = "foo"

<t:myComponent value="#{myBean.value}" />

// displays

<div>
    <input id="my_input" type="text" value="foo" />
    <button ...>update</button>
</div>

// user change input content by "bar"

// user click the update button

// myBean.value = "bar" now
robinvrd
  • 1,390
  • 8
  • 25
  • Look at the source of PrimeFaces components (or JSF components with ajax). They all have this in them. – Kukeltje Apr 14 '20 at 12:10

1 Answers1

0

Pass Bean Values to Javascript

There are some ways to do this. I think the most obvious way of doing this is rendering a script tag and putting the information in this.

Single Value:

writer.write("var value = '" + yourValue + "';");

Map Values:

String s = "var values = {";

for (Entry<String, String> entry : map.entrySet()) {
    s += entry.getKey() + ": '" + entry.getValue() + "',\n";
}

s = s.trim().substring(1, s.length() - 1); // removes last ','

s += "};";

writer.write(s);

List Values:

String s = "var values = [";

for (String value : list) {
    s += "'" + value + "', ";
}

s = s.trim().substring(1, s.length() - 1); // removes last ','

s += "];";

writer.write(s);

I would recommend not to put everthing in this script because this would be very much code in the encode methods. Rather have the static javascript code in a .js file and just write the dynamic content in the script tag. See how to get variables from other scripts.


Another way does not need a script tag. This way would call a js method like this:

function init(values) {
    // ...
}

In the Renderer just call the js method:

facesContext.getPartialViewContext().getEvalScripts().add("init(" + yourValue + ");");

Pass Javascript values to Server-Side

Just include an input like this:

// just a random unique id
String generatedId = context.getClientId(context) + ":utility";

// ...

writer.startElement("input", null);

writer.writeAttribute("id", generatedId, null);
writer.writeAttribute("name", generatedId, null);
writer.writeAttribute("type", "hidden", null);

writer.endElement("input");

Then pass the generatedId with the other values to javascript.


In Javascript:

function setValues(value) {
    // hiddenInputId is the server-side generatedId
    var input = document.getElementId(hiddenInputId);

    input.value = value;
}

Then just send an ajax request and get the values in the decode method like this:

// same id as in the encode methods
String generatedId = context.getClientId(context) + ":utility";

Map<String, String> map = facesContext.getExternalContext().getRequestParameterMap();

String value = map.get(generatedId);

// ...
fuggerjaki61
  • 812
  • 1
  • 9
  • 22