0

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>
Community
  • 1
  • 1
Gyro Gearloose
  • 1,056
  • 1
  • 9
  • 26
  • In HTML, the element is only available in DOM after the end tag is parsed. Make sure the script runs after the ``. I suggest working through some decent HTML DOM/JS tutorials to grasp its basic concepts. – BalusC Jan 16 '16 at 14:40
  • @BalusC yes, that is a mistake of mine. But putting the h:outputScript after the form doesn't help much. Still "this" is the window, and I can't use previousSibling as long as I don't have the (unfinished) parent or something else to start with. – Gyro Gearloose Jan 16 '16 at 14:52
  • Or is there a way (simple) to access the last node in the tree, no matter where it is nested? (I could do iteration, but that looks like overkill.) – Gyro Gearloose Jan 16 '16 at 14:55
  • Just get element by id? – BalusC Jan 16 '16 at 14:59
  • @BalusC how would I know the id? It is prepended with some stuff by jsf. – Gyro Gearloose Jan 16 '16 at 15:01
  • Just use `#{cc.clientId}` as base. See dupe answer. Your way of setting IDs is also awkward and only contributes more to confusion, but you've already been notified about that in some previous question. It's advisable to exactly follow the kickoff snippets and base the solution on that as long are you're new to the materials. – BalusC Jan 16 '16 at 15:08
  • @BalusC Great, thank you, this removes one of the problems. Still I get "window.document.getElementById("j_idt13") is null". – Gyro Gearloose Jan 16 '16 at 15:17
  • See "See also" links in your recently answered question. – BalusC Jan 16 '16 at 15:19

1 Answers1

-1

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

Youans
  • 4,801
  • 1
  • 31
  • 57
  • Bad advice. Firstly, `prependId="false"` is bad practice in JSF2 http://stackoverflow.com/q/7415230 Just use `#{cc.clientId}` as pointed out in comments and duplicates. Secondly, it'd also be nice if OP's another mistake was been pointed out in detail (`#{cc.attrs.id}` approach is nonsense). – BalusC Jan 16 '16 at 19:32
  • @BalusC: from your comment: "Secondly, it'd also be nice if OP's another mistake was been pointed out in detail (#{cc.attrs.id} approach is nonsense). " If so, why haven't you cared to mention? – Gyro Gearloose Jan 16 '16 at 19:40