function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Joe B.ax302Joe B.ax302 

{!$Component} in Form does not return an Id

Hi all, I'm not sure if this is expected functionality:

Code:
<apex:page >
    <script type="text/javascript">
        window.onload = new function() { alert('{!$Component.pbHelloWorld}'); alert('{!$Component.txtFoo}'); };
    </script>
    <apex:pageBlock id="pbHelloWorld" title="Hello, World">
    </apex:pageBlock>
    <apex:form>
        <apex:inputText id="txtFoo" />
    </apex:form>
</apex:page>

The id for the pageBlock will return; but not the one for the inputText.  

Does anyone know why this is?

I would also like to include an inputText field in a repeater or pageBlockTable and have the id be dynamically created for each row.  Asking too much?? :-) I know that this works visually:

Code:
<apex:pageBlock>
    <apex:pageBlockTable>
        <apex:column>
            <apex:form>
                <apex:inputText id="row" />
            </apex:form>
        </apex:column>
    </apex:pageBlockTable>
</apex:pageBlock>

 

Thanks in advance if anyone can help.
Ron HessRon Hess
here are some details on $component

To refer to a Visualforce component in JavaScript or another Web-enabled language you must specify a value for the id attribute for that component and then use that value with the $Component global variable in your code. Component IDs are accessed hierarchically on a page. For example, to access a data table with id="tableID" contained in a page block with id="blockID", use the following expression: $Component.blockID.tableID.

If the component you want to access is a direct descendant or a sibling of the $Component variable in the DOM hierarchy, you do not need to specify an ID for outer-level components. The system dynamically assigns IDs to the outer components and automatically determines the hierarchy for you.

For example, suppose you want to access a data table component that is contained in an <apex:pageBlock> tag. You only need to specify the ID for the <apex:dataTable> tag. This way, if the page hierarchy is ever changed (for example, if an <apex:detail> tag is wrapped around the table), you do not have to change your code.



basically you use $component from inside your visualforce tree, not in javascript

like this
   <apex:outputPanel layout="block">
<label for="checkbox">Click this box to change text font: </label>
<input id="checkbox" type="checkbox"
onclick="changeFont(this,'{!$Component.thePanel}');"/>
</apex:outputPanel>
<apex:outputPanel id="thePanel" layout="block">Change me!
</apex:outputPanel>


if it refers to a direct parent or sibling it should work.
The doc does say that if you provide a full dom path to the element it should work also,
so you would have to give the form an id , and use that in your $component expression



Joe B.ax302Joe B.ax302
Thank you Ron.  Your reply answered my first question perfectly.

Works like a charm:

Code:
<apex:page >
    <script type="text/javascript">
        window.onload = new function() {
            alert('{!$Component.pbHelloWorld}');
            alert('{!$Component.formFoo.txtFoo}');
            //alert(document.getElementById('txtFoo2').id);
            var divFoo = document.getElementById('divFoo');
            alert(divFoo);
        };
        
        function showValue() {
            var divFoo = document.getElementById('divFoo');
            alert(divFoo);
        }
    </script>
    <div id="divFoo"></div>
    <apex:pageBlock id="pbHelloWorld" title="Hello, World">
    </apex:pageBlock>
    <apex:form id="formFoo">
        <apex:inputText id="txtFoo" />
        <input type="text" id="txtFoo2" value="3" />
        <input type="button" value="..." onclick="showValue()" />
    </apex:form>
</apex:page>

 

jwetzlerjwetzler
to answer your second question, you'll want to give each of your container components ids like you did to solve your first question.  Then for each row, it will assign an incrementing number.  So this code:

Code:
<apex:page id="thePage" standardController="account">
<apex:pageBlock id="thePageBlock"> <apex:pageBlockTable value="{!account.contacts}" var="contact" id="theTable"> <apex:column id="theColumn"> <apex:form id="theForm"> <apex:inputText id="row" /> </apex:form> </apex:column> </apex:pageBlockTable> </apex:pageBlock>
</apex:page>

if you look at the source, gives you these ids (assume I have two contacts on that account, so it prints out two rows)
"thePage:thePageBlock:theTable:0:theForm:row"
"thePage:thePageBlock:theTable:1:theForm:row"
A word of advice though on that code.  In general it is a bad idea to have a form within an iterating component.  It's probably best for you to move the form outside of the pageBlock, otherwise you are generating a form for every row.
 



Message Edited by jwetzler on 05-30-2008 09:48 AM
Joe B.ax302Joe B.ax302
So I wrote this controller extension:

Code:
public class jhbAccountExtension {

    private final Account acct;
    Integer input;
    
    public jhbAccountExtension(ApexPages.StandardController controller) {
        this.acct = (Account)controller.getRecord();
    }
    
    public Integer getInput() {
        return input;
    }
    
    public void setInput(Integer i) {
        input = i;
    }
    
    public void doIt() {
        input = input * 100;
    }
}

 
And I wrote this visual force code... the idea is to multiple the value in the input box by 100

Code:
<apex:page id="thePage" standardController="account" extensions="jhbAccountExtension">
    <apex:form id="theForm">
        <apex:pageBlock id="thePageBlock">
            <apex:pageBlockTable value="{!account.contacts}" var="contact" id="theTable" style="width: 600px">
                <apex:column value="{!contact.name}" />
                <apex:column id="theColumn" headervalue=".">
                    <apex:inputText id="row" value="{!input}"/>
                </apex:column>
                <apex:column id="theColumn2" headervalue=".">
                    <apex:commandButton id="btn" value="Do It!" action="{!doIt}" reRender="row" />
                </apex:column>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>

 
I'm able to get it working in Javascript with the following source:

Code:
<apex:page id="thePage" standardController="account" extensions="jhbAccountExtension">
    <script type="text/javascript">
        function display(buttonSender) {
            var strToParse = buttonSender.id;
            var pos  = strToParse.indexOf(':theTable');
            var length = strToParse.length;
            var pos2 = strToParse.indexOf(':btn');
            var pos3 = strToParse.indexOf(':', pos + 1);
            var subString = strToParse.substr(pos + 10, pos2 - pos3 - 1);
            var findThisElement = strToParse.substr(0, pos + 10);
            findThisElement = findThisElement + subString + ':row';
            var rowInput = document.getElementById(findThisElement);
            alert(rowInput.value);
            rowInput.value = rowInput.value * 100;
        }
        
    </script>
    <apex:form id="theForm">
        <apex:pageBlock id="thePageBlock">
            <apex:pageBlockTable value="{!account.contacts}" var="contact" id="theTable" style="width: 600px">
                <apex:column value="{!contact.name}" />
                <apex:column id="theColumn" headervalue=".">
                    <apex:inputText id="row" />
                </apex:column>
                <apex:column id="theColumn2" headervalue=".">
                    <apex:commandButton id="btn" value="Do It!" onclick="display(this)" reRender="row" />
                </apex:column>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>

 
I'd like to stay away from Javascript if possible.  Any thoughts?  Thanks!

Joe B.ax302Joe B.ax302
Sorry jwetzler,  I forgot to say thank you for the post.  Your reply was very insightful. Thanks.