How do I pass JSF managed bean properties to a JavaScript function?

I would like to know how I can pass JSF managed bean properties to a JavaScript function.

Something like this:

<script>
  function actualizaMenu(key){
    #{linkedMenu.setKey(key)}
  }
</script>
<ul>
  <ui:repeat value="#{moduleList.modulos}" var="entity">
    <li>
      <a onclick="actualizaMenu(#{entity.key})">#{entity.nombre}</a>
    </li>
  </ui:repeat>
</ul>

Solution 1:

This is not exactly "passing" of JSF variables. This is just printing JSF variables as if they are JavaScript variables/values. You know, JSF and JS do not run in sync at all. JSF runs in webserver and produces HTML/CSS/JS code which in turn runs in webbrowser once arrived over there.

Your concrete problem is most likely caused because you wrote JSF code in such way that it generates invalid JS syntax. An easy way to verify that is by just checking the JSF-generated HTML output which you can find by rightclick, View Source in browser, and by checking if you don't see any syntax error reports in the JS console in browser which you can find by pressing F12 in Chrome/IE9+/Firefox23+.

Imagine that #{entity.key} here

<a onclick="actualizaMenu(#{entity.key})">#{entity.nombre}</a>

prints a Java string variable like "foo", then the generated HTML would look like

<a onclick="actualizaMenu(foo)">some name</a>

But hey, look, that represents a JavaScript variable named foo, not a JS string value! So if you actually want to ultimately end up as

<a onclick="actualizaMenu('foo')">some name</a>

then you should instruct JSF to generate exactly that HTML:

<a onclick="actualizaMenu('#{entity.key}')">#{entity.nombre}</a>

Beware of special characters in the JSF variable though. You can use OmniFaces of:escapeJS() function for that.


Unrelated to the concrete problem, the concrete implementation of actualizaMenu() makes no sense. You seem to be attempting to set a bean property. You should not use JS for that, but a <h:commandLink> instead.

<h:commandLink value="#{entity.nombre}" action="#{linkedMenu.setKey(entity.key)}" />

Nest if necessary a <f:ajax> to make it asynchronous.

Solution 2:

I would recommend using event binding with jQuery and the data attribute on elements to get the same result (assuming you use jQuery):

<script>
  function actualizaMenu(key){
    /* Logic here ... */
  }

  $(document).ready(function(){
    $('.menuItem').click(function(){
      var key = $(this).data('key');
      actualizaMenu(key);
    );
  });
</script>

...

<ul>
  <ui:repeat value="#{moduleList.modulos}" var="entity">
    <li>
      <a data-key="#{entity.key}" class="menuItem">#{entity.nombre}</a>
    </li>
  </ui:repeat>
</ul>

And, as pointed out elsewhere, unless #{linkedMenu.setKey(key)} actually returns a piece of javascript (which seams unlikely and would probably be really bad even if it did) you need to fix the function as well.

Solution 3:

I know this question is old, but to those who are still looking there's an alternative.

If you are using primefaces just try this out. Request Context