0

So my task is to get two dates from user and based on that do some fancy logic which will result in creation of table with data requested.

To begin with i wanted to create small VFpage with two input fields and button. Clicking on button would reload part of the page and populate it with the table filled with data.

My problem is that after i provide dates i do not see them moved to controller and i do not know if they should be or is set method only triggered at begining of the page load?

Here is Page:

<apex:page controller="pageGenerator" docType="html-5.0">
    <apex:form >
         <script>
            function sideSetter()
            {
                dataSetter();
                document.getElementById('{!$Component.mainform.mainBlock.mainDisplay}').innerHTML = '{!mainTableArea}';
            }
        </script>
        <apex:actionFunction name="dataSetter" action="{!dataSetter}" rerender="mainform.mainDisplay"/>
    </apex:form>
    <apex:form id="mainform">
        <apex:pageBlock title="dynamictest" id="mainBlock">
            <apex:pageBlockSection title="Filters" id="mainWork" columns="1">
                <apex:input title="Start date" label="Start date" type="date" value="{!startDate}"/>
                <apex:input title="End date" label="End date" type="date" value="{!endDate}"/>
                <apex:commandButton value="Generate" onclick="sideSetter();" rerender="mainform.mainDisplay"/>
            </apex:pageBlockSection>
            <apex:pageBlockSection title="renderedpart" id="mainDisplay">
                Nothing yet....
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>    
</apex:page>

and here is controller:

public class pageGenerator
{

    // VF page variable
    public String mainTableArea {get;set;}
    public Date startDate {get;set;}
    public Date endDate {get;set;}

    public pageGenerator()
    {
        mainTableArea = 'nnothing';
    }

    // Display logic
    public PageReference dataSetter()
    {
        setMainTableArea( String.valueOf(startDate) + ' ' + String.valueOf(endDate) );
        system.debug( MainTableArea + ' ' + String.valueOf(startDate) + ' ' + String.valueOf(endDate) );

        return null;
    }

    private void setMainTableArea( String theString )
    {
        this.mainTableArea = theString;
    }
}

the second set class is result of me trying to establish what is wrong. What i want to see is after i put some date in inputfields and clikc the button i want the bottom block to be rerendered with the dates i provided. From there i think i can handle rest. But for some risen endDate sometimes is geting it value saved when startDate and mainTableArea do not get change. and i always get nnothing there instead of what i want.

May i please get explentation on why is that? Is my understanding of get and set methods wrong? How to make the values move and to show what i need in there ?


Update 28.02.2019

I managed to make part of the page change as i wish it to and now my function is triggering. But what stopped working is that now date field again do not provide values to controller. So i end up always with same defoult valuesi set up in controller. Any idea what could cause that?

New code! Page:

<apex:page controller="pageGenerator" docType="html-5.0">
    <apex:form>
        <apex:actionFunction name="setData" action="{!dataSetter}" rerender="mainform"/>
    </apex:form>           
    <apex:form id="mainform">
        <apex:pageBlock title="dynamictest" id="mainBlock">
            <apex:pageBlockSection title="Filters" id="mainWork" columns="1">
                <apex:input title="Start date" label="Start date" type="date" value="{!startDate}"/>
                <apex:input title="End date" label="End date" type="date" value="{!endDate}"/>
                <apex:commandButton value="Generate" onclick="setData(); return false;" rerender="mainform.mainBlock.mainWork"/>
            </apex:pageBlockSection>
            <apex:pageBlockSection title="renderedpart" id="mainDisplay">
                {!mainTableArea}
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>    
</apex:page>

Update 04.03.2019

I found out that if i will use some funny date like year 41000 then the get set methods do not work correctly. Some of my problems are gone just cause i started using dates like 12.01.2010 ... :P Thx salesforce...

2
  • 1
    `rerender="mainDisplay" should be sufficient; that said, you should be using different idiom for your getter/setter and avoid the javascript entirely. A helpful resource is developerforce.com/guides/Visualforce_in_Practice.pdf
    – cropredy
    Commented Feb 27, 2019 at 22:58
  • @cropredy thx for first clue i will start from it. But what do you mean by different idiom for getter setter ? Commented Feb 28, 2019 at 7:58

2 Answers 2

1

Here's something to help you along

The commandButton, when clicked will transmit (everything inside the apex:form) - i.e. the apex:input elements to the controller's setters. The onclick attribute is not needed. Nor is the dataSetter method

Because the order of execution for controller getters is indeterminate, you should write the getters to be idempotent

public Date start {
  get {
    if (start == null) [
      start = Date.today();  // default value
    }
    return start;
  } set;
}
...
public List<Opportunity> filteredOpportunities {
  get {
    return [SELECT id, CloseDate, Account.Name FROM Opportunity
         WHERE CloseDate >= :this.startDate AND CloseDate <= :this.endDate];
  } private set;
}

Obviously, this is only an example and you'll need to customize it but less-is-more in VF. Avoid proceduralism except inside of the limited scope of an action method

4
  • So what you say is that we can't really control or make sure when what will be triggered? Cause what i want is that right after button being clicked i want values to be sent to setter so that i can use them in my SOQL in controller and gather records from that period. Then i want to do aloooot on that that few more SOQL's and then change variable mainTableArea so that it will have information i generated. So i can deal with all of the logic in between what i need is a way to force order of events some how... : By the way thx for answer! :D And plis some more info Commented Mar 1, 2019 at 9:16
  • So the function you say is not needed on the onclick atribute is really going to be the whole huge function that will work with my logic. So i need it to trigger after values of startDate and endDate will be transfered. Commented Mar 1, 2019 at 11:24
  • 1
    The whole point is that command button when clicked sends the form elements to your setters, then the page is refreshed by invoking the getters.
    – cropredy
    Commented Mar 1, 2019 at 15:49
  • The man is right!!! All needed is : <apex:commandButton value="Generate" action="{!dataSetter}"/> and everything works fine! Commented Mar 4, 2019 at 14:49
0

So in the end i feel I over did it. Thx for hints that i should make it simpler.

Page code:

<apex:page controller="pageGenerator" docType="html-5.0">          
    <apex:form id="mainform">
        <apex:pageBlock title="dynamictest" id="mainBlock">
            <apex:pageBlockSection title="Filters" id="mainWork" columns="1">
                <apex:input title="Start date" label="Start date" type="date" value="{!startDate}"/>
                <apex:input title="End date" label="End date" type="date" value="{!endDate}"/>
                <apex:commandButton value="Generate" action="{!dataSetter}" rerender="mainform"/>
            </apex:pageBlockSection>
            <apex:pageBlockSection title="renderedpart" id="mainDisplay">
                <apex:outputText value="{!mainTableArea}" escape="false" /> <br/>
                {!startDate}<br/>
                {!endDate}
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>    
</apex:page>

Controller code:

public class pageGenerator
{
    // Support classes
    private class DayInfo
    {
        Boolean isWorkDay;
        Map<String,Integer> timeUsed;

        public DayInfo()
        {
            isWorkDay = true;
            timeUsed = new Map<String,Integer>();
            timeUsed.put( 'Total', 0 );
        }

        public DayInfo( Datetime theDate, String bHoursId )
        {
            isWorkDay = BusinessHours.isWithin( bHoursId , theDate );
            timeUsed = new Map<String,Integer>();
            timeUsed.put( 'Total', 0 );
        }

    }
    // VF page variable
    public String mainTableArea {get; private set;}
    public Date startDate {get;set;}
    public Date endDate {get;set;}

    public void setstartDate( Date value )
    {
        this.startDate = value;
    }

    // Logic variables
    private Map<Date,DayInfo> thePeriod;
    private BusinessHours bh;

    //Constructor
    public pageGenerator()
    {
        system.debug('MainConstructor Triggered');
        mainTableArea = ' <table style="width:100%"> <br/> <tr> <th>Firstname</th> <th>Lastname</th> <th>Age</th> </tr> <tr> <td>Jill</td> <td>Smith</td> <td>50</td> </tr> <tr> <td>Eve</td> <td>Jackson</td> <td>94</td> </tr></table> ';
        startDate = Date.today();
        endDate = Date.today().addMonths(1);
        bh = [SELECT Id FROM BusinessHours WHERE IsDefault=true];

    }

    // Display logic
    public PageReference dataSetter()
    {
        this.setMainTableArea( String.valueOf(startDate) + ' ' + String.valueOf(endDate) );
        system.debug( MainTableArea + ' ' + String.valueOf(startDate) + ' ' + String.valueOf(endDate) );

        return null;
    }

    private void setMainTableArea( String theString )
    {
        this.mainTableArea = theString;
    }


    // Working Days logic

        // Will count number of days for each project
    public integer numOfWorkDays( Date startDate , Date endDate )
    {
        integer result = 0;
        Date dateHolder = startDate;
        do
        {
            if( thePeriod.get( dateHolder ).isWorkDay ) ++result;
            dateHolder.addDays( 1 );
        }
        while( dateHolder<=endDate );

        return result;
    }

}

So to help you guys who will have similar issue in future. Try no to use onclick cause it is problematic about when does it really happen. What is more it makes the regular thing that buttons does ( which is sending form elements to controller ) not working.

Often if something is not working you just need to set up rerender parameter on button ( magic ).

Keep it simple guys.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .