Jul 13, 2011 11:58 AM
23 Posts

Accessing Fields in a repeat control

  • Category: Server Side JavaScript
  • Platform: All
  • Release: 8.5.2
  • Role: Developer
  • Tags: Repeat Control,edit box
  • Replies: 6
ok, here is my issue.
I have a custom control that contains a text field and an associated label.  The control is inserted into a repeat control.  I have a second control that in the beforeRenderResponse gets a list of fields with errors using facesContext.getClientIdsWithMessages() I then loop thru the client ids and get a handle on the individual fields with getComponent(@RightBack(clientId,":")) then set a styleClass and a few other things on the field.  This works great as long as the fields are on the top level... 
 
the long story short question is how can I get a handle on an individual instance of a field in a repeat control?
 
 
 
Jul 13, 2011 1:11 PM
129 Posts
Re: Accessing Fields in a repeat control
If you just need to style invalid fields, take a look at this:
http://dontpanic82.blogspot.com/2011/07/xpages-styling-invalid-field.html 
Jul 14, 2011 10:38 AM
23 Posts
Re: Accessing Fields in a repeat control
while that is really cool and good to know it doesn't give me what I'm looking for.
 
I have a custom error control that gets a handle on the fields that have messages and then grabs their label, using the getLabelFor(input) method, to build the error message block like this...
 
Error Box Header
 
Field Label: Error Message Detail.
Field Label: Error Message Detail.
Field Label: Error Message Detail.
  
Error Box footer
 
This all works except for fields in a repeat control which I can't get a handle on using 
 
var input:javax.faces.component.UIComponent = getComponent(@RightBack(clientId,":"));
Jul 14, 2011 11:44 AM
129 Posts
Re: Accessing Fields in a repeat control
Try this, if you already know the clientId:
var component = view.findComponent( clientId.replace( view.getClientId( facesContext ), '' ) );
Jul 14, 2011 1:15 PM
23 Posts
Re: Accessing Fields in a repeat control
nope that didn't work...
 
here is the source for the control maybe I'm missing something...
 
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

    <xp:this.beforePageLoad><![CDATA[#{javascript:if(param.containsKey("showmsg")){
    var dummyAlerts = [{
        "title":"This is a sample info",
        "type":"Info",
        "messages":[
            {"detail":"Details with out a label"},
            {"label":"Label no detail"}
        ]
    },
    {
        "title":"This is a sample warning",
        "type":"Warning",
        "messages":[
            {"label":"","detail":"Details with out a label"},
            {"label":"Label2","detail":"Message details goes here"}
        ]
    },
    {
        "title":"This is a sample Error",
        "type":"Error",
        "messages":[
            {"label":"Label","detail":"Message details goes here"},
            {"label":"Label2","detail":"Message details goes here"}
        ]
    },
    {
        "title":"This is a sample Confirm",
        "type":"Confirm",
        "messages":[
            {"label":"Label","detail":"Message details goes here"},
            {"label":"Label2","detail":"Message details goes here"}
        ]
    },
    {
        "title":"",
        "type":"Confirm",
        "messages":[
            {"label":"Label","detail":"This message box has no title"}
        ]
    }];
    sessionScope.put("appMessages", dummyAlerts)
}
}]]></xp:this.beforePageLoad>

    <xp:this.afterRenderResponse><![CDATA[#{javascript:sessionScope.remove("appMessages")}]]></xp:this.afterRenderResponse>
    <xp:this.beforeRenderResponse><![CDATA[#{javascript:if(sessionScope.containsKey("previousMessages")){
      var pClientIds:Array = sessionScope.get("previousMessages");
      for (var x=0;x<pClientIds.length;x++){
            var pInput:javax.faces.component.UIComponent = getComponent(pClientIds[x]);
            if(pInput!= null){
                  pInput.styleClass = String(@ReplaceSubstring(pInput.styleClass,"lotusError ", ""));
            }           
      }
      sessionScope.remove("previousMessages")                  
}

var clientIds:Iterator = facesContext.getClientIdsWithMessages();
var previousMessages:Array = new Array();
var curMessages:appMessageBox = new appMessageBox();
while (clientIds.hasNext()){
    curMessages.title = sessionScope.get("formErrorTitle");
    curMessages.type="Error"
    var clientId:String = clientIds.next();
    var thisId:String = @RightBack(clientId,":")    
    //var input:javax.faces.component.UIComponent = getComponent(thisId);
    var input:javax.faces.component.UIComponent = view.findComponent( clientId.replace( view.getClientId( facesContext )+":", '' ));
    if(input!= null && !(input.isValid())){
        var messagesIter:Iterator = facesContext.getMessages(clientId);
        var label:javax.faces.component.UIComponent = getLabelFor(input);
        previousMessages.push(thisId);
        while(messagesIter.hasNext() ){
            var messageObj:javax.faces.application.FacesMessage = messagesIter.next();
            var curMsg:appMessage = new appMessage();
            curMsg.label = ((label!=null)?label.getValue():"");
            curMsg.detail = messageObj.getSummary();
            curMessages.messages.push(curMsg)
        }
        input.styleClass = "lotusError " + input.styleClass
    }
}
if(curMessages.messages.length > 0){
    var newMsgs = null;
    if(sessionScope.containsKey("appMessages")){
        newMsgs = sessionScope.get("appMessages");
    }else{
        newMsgs = new Array();
    }
    newMsgs.push(curMessages);
    sessionScope.put("appMessages",newMsgs);
    
}
if (previousMessages.length > 0){
      sessionScope.put("previousMessages",previousMessages)
}
}]]></xp:this.beforeRenderResponse>
    <xp:repeat id="msgBox" rows="5" value="#{sessionScope.appMessages}"
        indexVar="i" var="msgObj">
        <xp:panel>
            <xp:this.styleClass><![CDATA[#{javascript:"lotusMessage lotus" + msgObj.type}]]></xp:this.styleClass>
            <xp:image url="/blank.gif" id="image1"></xp:image>
            <xp:text escape="true" id="msgBoxTitle" styleClass="lotusBold lotusBig"
                value="#{javascript:msgObj.title}">
                <xp:this.rendered><![CDATA[#{javascript:(msgObj.title != null && msgObj.title != "")}]]></xp:this.rendered>
            </xp:text>
            <xp:repeat id="msgDetail" rows="10"
                value="#{javascript:msgObj.messages}" var="msgDtlObj" indexVar="d">
                <xp:span>
                    <xp:text escape="true" id="msgDtlTitle" styleClass="lotusMessageTitle"
                        value="#{javascript:msgDtlObj.label}">

                        <xp:this.rendered><![CDATA[#{javascript:msgDtlObj.label != null && msgDtlObj.label != ""}]]></xp:this.rendered>
                    </xp:text>
                    <xp:text escape="true" id="msgDtlDetail" styleClass="lotusMessageDetail"
                        value="#{javascript:msgDtlObj.detail}">
                        <xp:this.rendered><![CDATA[#{javascript:msgDtlObj.detail != null && msgDtlObj.detail != ""}]]></xp:this.rendered>
                    </xp:text>
                </xp:span>
            </xp:repeat>
        </xp:panel>
    </xp:repeat>
</xp:view>

Jul 15, 2011 2:59 PM
24 Posts
Re: Accessing Fields in a repeat control
 I'm not sure if this is what you need, but I have a situation where I need to get the id of controls that are created inside a repeat control.
 
At run time, I never know how many controls there are going to be.  
 
What I do is give the target control  a "throwaway" css style class name, like "myCustomControl".  
Then, when I need to process the controls, I use dojo.query(".myCustomControl") to get an array of all the nodes in the DOM with my target CSS class. 
 
Hope this helps, 
 
-- Jeff 
 
 
Jul 19, 2011 2:42 PM
129 Posts
Re: Accessing Fields in a repeat control
I did a little testing and had the same issue as you.
 
I got a little help from this page: 
http://www.icefaces.org/JForum/posts/list/6760.page;jsessionid=C1870B4FADF8F7EB0DF4CB747BAD09AB 
 
Try this instead of the other findComponent I posted: 
view.findComponent( clientId.replace( view.getClientId( facesContext ), '' ).replace( /\:\d*\:/g, ':' ) ); 
 
To test, I wrote a very simple custom control that shows the error messages similar to what you wanted. It also generates a link on the error message. When the error message is clicked, the field with the error gets focus.
 
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
 <xp:this.beforeRenderResponse><![CDATA[#{javascript:var messageObjects = [];
var clientId, clientIds = facesContext.getClientIdsWithMessages();
while( clientIds.hasNext() ){
clientId = clientIds.next();
var component = view.findComponent( clientId.replace( view.getClientId( facesContext ), '' ).replace( /\:\d*\:/g, ':' ) );
if( !component ){ continue; }

var message = '', messages = facesContext.getMessages( clientId );
while( messages.hasNext() ){
message += (message) ? ', ' : '' + messages.next().getSummary();
}

var labelComponent = getLabelFor( component );
var label = ( labelComponent ) ? labelComponent.getValue() : '';

messageObjects.push({
clientId: clientId,
label: label,
message: message
});
}

 viewScope.messageObjects = messageObjects;}]]></xp:this.beforeRenderResponse>
<xp:this.resources>
<xp:script src="/UtilitiesSSJS.jss" clientSide="false"></xp:script>
</xp:this.resources>
<xp:div styleClass="xspMessage"
rendered="#{javascript:return ( getComponent( 'messageRepeat' ).getRowCount() > 0 );}">
<xp:repeat id="messageRepeat" rows="30" value="#{viewScope.messageObjects}" var="messageObject">
<xp:this.facets>
<xp:text value="Validation errors:" xp:key="header" tagName="strong" />
</xp:this.facets>
<br />
<a href="#" onclick="dojo.byId('#{messageObject.clientId}').focus();return false;">
<xp:text value="#{messageObject.label} #{messageObject.message}" />
</a>
</xp:repeat>
</xp:div>
</xp:view>