Search code examples
javascriptjsf-2encapsulation

Encapsulating javascript code inside a composite with jsf-2


I asked this Is it possible to add a javascript function to a h:form in jsf2? but it was closed as a duplicate, with a link to this https://stackoverflow.com/a/29129816/4142984 answer.

Perhaps in my question I didn't make it clear enough what I want to do: I want to have a composite the internal structure of which may change in future versions. I want this composite to have a javascript function that can be called from outside to handle all the internal details, encapsulated within the composite with no parts of the code outside.

<h:form onload="this.myfunc=function(){alert('Hello world');}" ...

would do the trick, but there is no "onload" for h:form.

This way, the page that uses the composite need not be changed when the structure of the composite is changed.

The supposed answer has two parts. The part labeled "2.)" does not address my question at all, as it requires javascript outside the composite.

The part labeled "1.)" looks better, but I can't get it to work.

I put the following inside the h:form of my composite:

<h:outputScript>alert("Now"+this+'#{cc.attrs.imgId}');window.document.getElementById('#[cc.attrs.imgId}').myfunc=function() {alert("newly called"+#{mBean.keyX})}</h:outputScript>

But this fails. Firstly, "this" is the window, not my "form". And secondly, getElementById doesn't find the element, clearly because the id is changed by jsf.

So what can I do to make it work?

Edit: thanks to the hints and answers, the following code works:

<composite:implementation>
    <h:form id="${cc.attrs.imgId}" styleClass="small">
        <f:event type="postAddToView" listener="#{mBean.register}" />
        <f:attribute name="myId" value="hmta${cc.attrs.imgId}" />
        <h:graphicImage width="${cc.attrs.width}" id="${cc.attrs.imgId}"
            onclick="this.nextSibling.value=mods(event)" onmouseover="aa=this.id"
            value="images/img?#{cc.attrs.flav}=#{Math.random()}">
            <f:ajax event="click" execute="@this k"
                listener="#{mBean.handleEvent}" render="@this">
            </f:ajax>
        </h:graphicImage>
        <h:inputHidden id="k" value="#{mBean.keyX}" />
    </h:form>
    <h:outputScript>window.document.getElementById('#{cc.clientId}:#{cc.attrs.imgId}').myfunc=function() {alert("newly called"+#{mBean.keyX})};</h:outputScript>
</composite:implementation>

Solution

  • First

    Call composite component by providing an ID :

    <core:yourComposite id="someId" .../>
    

    Second

    You add prependId=false on your h:form attributes to prevent automatic ids and provide id for that form

    Now you an inspect the rendered html you will see the form with mapped semantic id like : someId:formId now you can inject your script within the form calling:

    getElementById('#{cc.attrs.id}:formId') very normally