[SalesForce] Add logic in VisualForce Page within apex repeat

Is it possible to put logic within apex:repeat in VisualForce page? I have code as shown below but instead of executing logic of array split and then displaying table contents, visual force page is displaying entire string prop as defined below and then the table row

<table>
    <tr>
        <td>Head 1</td>
        <td>Head 2</td>
        <td>Head 3</td>
        <td>Head 4</td>
    </tr>    
    <apex:repeat value="{!queries}" var="query">
     string[] prop = ({!query.MyField}).Split('\n');
     for (string s :prop)
     {
        if (s.Contains('='))
        {
            <tr>    
               <td>{!query.Field1}</td>
               <td>{s[0]}</td>
               <td>{!query.Field2}</td>
               <td>{s[1]}</td>
           </tr>
      }
     }
    </apex:repeat>
</table>

I can't modify controller since it is managed and I have no access to source code.

Best Answer

While you can have some logic within repeat tags, you can't include literal Apex Code. You could, however, achieve this with either JavaScript (albeit clumsily), or by rendering this data with a wrapper class and some helper functions.

You'll see you have to use "formula-like" constructs, so it has some limitations (e.g. you can't get the a string into an array using pure Visualforce). A close approximation of what you could write might look like this:

<apex:repeat value="{!queries}" var="query">
    <apex:repeat value="{!query.MySplitField}" var="splitPart">
        <apex:outputText rendered="{!CONTAINS(splitPart,'=')}">
            <tr>
                <td>
                    {!query.Field1}
                </td>
                <td>
                    {!LEFT(splitPart, FIND(splitPart,'='))}
                </td>
                <td>
                    {!query.Field2}
                </td>
                <td>
                    {!RIGHT(splitPart, FIND(splitPart,'='))}
                </td>
            </tr>
        </apex:outputText>
    </apex:repeat>
</apex:repeat>

However, you'll have to "wrap" your records into a wrapper class:

public class Wrapper {
    MySObject record;
    Wrapper(MySObject record) {
        this.record = record;
    }
    public String[] getMySplitField() {
        if(record.MyField != null) {
            return record.MyField.split('\n');
        }
        return new String[0];
    }
    public String getField1() {
        return record.Field1;
    }
    public String getField2() {
        return record.Field2;
    }
}

You add records to the wrapper like so:

public Wrapper[] getQueries() {
    Wrapper[] results = new Wrapper[0];
    for(MySObject record:[SELECT MyField, Field1, Field2 FROM MySObject]) {
        results.add(new Wrapper(record));
    }
    return results;
}

As JavaScript, it'd probably be easier to just make a remote call for the data and then render it (perhaps by using jQuery). You could probably, however, expose the "queries" data simply by doing the following:

<script>
    var queries = {!queries};
    $.each(queries, function(i,v) {
        $.each(v.MyField.split("\n"), function(i2,v2) {
            if(v2.match(/=/)) {
                // Render the desired elements
            });
        });
</script>

This might get tricky if you're trying to use reRenders and so on, but is certainly possible.

Related Topic