+ Start a Discussion
jason.bradleyjason.bradley 

Attempt to de-reference a null object? Visitor log prototype

Hello to all,

 

I am working on a VisualForce page that would serve as a visitor log at a front desk or something such as that.

This is a learning experience of sorts, so the solution to my problem may very well be simple and I just have not caught it.

The error I recieve upon opening up my VisualForce page says "Attempt to de-reference a null object". Any other errors I have encountered thus far were fixable because the error page had a little more detail than this.

 

Here is my VF page:

<apex:page controller="VisitorLogController" sidebar="false">
    <apex:sectionHeader title="Visitor Log"/>
    
    <div style="text-align:center;">
    <apex:form id="visitorLogForm">
        <div style="float:left;width:25%;">
            Visitor Name: <apex:inputText value="{!visitorName}"/>
        </div>
        <div style="float:left;width:25%;">
            Company Name: <apex:inputText value="{!company}"/>
        </div>
        <div style="float:left;width:25%;">
            Title in Company: <apex:inputText value="{!title}"/>
        </div>
        <div style="float:right;width:25%;">
            <apex:commandButton action="{!checkIn}" value="Check In"/>            
        </div>
        
        <apex:pageBlock>
            <apex:pageBlockTable value="{!logEntriesCheckedIn}" var="log" id="logEntryTable" rendered="{!recordsObtained}">
                <apex:column value="{!log.Visitor_Name__c}"/>
                <apex:column value="{!log.Company__c}"/>
                <apex:column value="{!log.Title__c}"/>
                <apex:column headerValue="Check Out">
                    <apex:commandButton value="Check Out"/>
                    <apex:actionSupport event="onclick" action="{!checkOut}" rerender="true">
                        <apex:param name="logID" value="{!log.Name}"/>
                    </apex:actionSupport>
                </apex:column>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
    </div>
</apex:page>

 

This is my controller:

public class VisitorLogController {
    
    public String visitorName {get; set;}
    public String company {get; set;}
    public String title {get; set;}
    
    public Boolean recordsObtained {get; set;}
    
    public List<Visitor_Log_Entry__c> logEntries {get; set;}
    public List<Visitor_Log_Entry__c> logEntriesCheckedIn {get; set;}
    
    public VisitorLogController() {
        recordsObtained = false;
        logEntries = [Select Name, Visitor_Name__c, Title__c, Company__c, Contact__c, Checked_In__c, Time_In__c, Time_Out__c from Visitor_Log_Entry__c limit 1000];
        for (Visitor_Log_Entry__c l : logEntries)
        {
            if (l.Checked_In__c == true)
                logEntriesCheckedIn.add(l);
        }
        recordsObtained = true;
    }
    
    public PageReference checkIn()
    {
        Account account = new Account(Name=company);
        upsert account;
        
        Contact contact = new Contact(FirstName=visitorName.split(' ', 2)[0], LastName=visitorName.split(' ', 2)[0], Job_Position__c = title, Account = account);
        upsert contact;
        
        Visitor_Log_Entry__c newEntry = new Visitor_Log_Entry__c(Checked_In__c = true, Company__c = company, Contact__c = contact.id, Time_In__c = System.now(), Title__c = title, Visitor_Name__c = visitorName);
        insert newEntry;
        
        return null;
    }
    
    public PageReference checkOut()
    {
        String entryID = ApexPages.currentPage().getParameters().get('logID');
        Visitor_Log_Entry__c focusEntry = [Select Name, Checked_In__c, Time_Out__c from Visitor_Log_Entry__c where name = :entryID limit 1];
        
        focusEntry.Checked_In__c = false;
        
        Datetime nowLocal = System.now();
        
        focusEntry.Time_Out__c = nowLocal;
        
        update focusEntry;
        return null;
    }
}

 

A great many thanks to anyone that is willing to help lead me in the right direction. I would also appreciate any other pointers that can be given as well, I am not all that sure I have taken the best approach to some of the working of this page.

Best Answer chosen by Admin (Salesforce Developers) 
Jay EcklesJay Eckles

Just glancing it looks like perhaps you didn't create logEntriesCheckedIn.  You'd need something like

logEntriesCheckedIn = new List<Visitor_Log_Entry__c>() ;

 before you could call logEntriesCheckedIn.add.  I may be wrong about that, though.  The way to get more info is to set up a debug log.  Go to setup>Monitoring>Debug Logs and add a new monitor for whatever user you're developing/testing with.  Once that's done, then go access your visitor log again and trigger the error.  Then, go back to the debug log list, refresh it, and you should see a log for VisitorLogController and/or the VF page.  

 

You can use System.Debug(String) calls in your code to provide breadcrumbs in the debug log if that helps.

 

Good luck.

All Answers

Jay EcklesJay Eckles

Just glancing it looks like perhaps you didn't create logEntriesCheckedIn.  You'd need something like

logEntriesCheckedIn = new List<Visitor_Log_Entry__c>() ;

 before you could call logEntriesCheckedIn.add.  I may be wrong about that, though.  The way to get more info is to set up a debug log.  Go to setup>Monitoring>Debug Logs and add a new monitor for whatever user you're developing/testing with.  Once that's done, then go access your visitor log again and trigger the error.  Then, go back to the debug log list, refresh it, and you should see a log for VisitorLogController and/or the VF page.  

 

You can use System.Debug(String) calls in your code to provide breadcrumbs in the debug log if that helps.

 

Good luck.

This was selected as the best answer
jason.bradleyjason.bradley

Thank you very much and a quick reply too! It's always the little things that seem to get me, but that was exactly what it needed. Now I just need to figure out how to make sure upsert works correctly, because at this point it's just adding new Accounts and Contacts with the same information to the database. Is there an ID or something other than Name that is used to tell these records apart or am I going to do the work of the upsert DML call and write some if statements and such to check if the records already exist before adding them?

Jay EcklesJay Eckles

Yes, there is a field called Id that is the one and only primary key.  If you create an Account object with a name and then upsert it, it will always create a new record with the same name but a new ID.

 

You could try something like 

Account account = [Select Id, Name from Account where Name=:company] ;
if( account == null ){ account = new Account( Name=company ) ;}
upsert account ;

 That will create a new account if one does not exist with a name matching (exactly) the value of the company variable.

 

By the way, if you changed your Visitor_Log_Entry__c.Company__c field from (what I suspect is) a text field to a lookup field on Account, then you can link your log entry and account records.  Ditto for contact.  E.g.,

Visitor_Log_Entry__c newEntry = new Visitor_Log_Entry__c( Company__c = account.Id, Contact__c = contact.Id, ... ) ;

 

jason.bradleyjason.bradley

Ah alright, thanks! I'll need to remember that in the future. One last question, I swear. How would I find a list view of every record of a custom object if my company is out of tabs? I have scoured the UI for something that will allow me to see every record of the Visitor_Log_Entry__c object, but from what I've found it would require a tab for that object.

 

Good point about the company field, that should make things a lot easier.

Jay EcklesJay Eckles

A report, perhaps?  You'd need to create a custom report type first since it's a custom object.

 

Another option would be a visualforce page that simply displays all the records.  You could bookmark it or link to it from somewhere.

jason.bradleyjason.bradley

Hmm...That's what I was afraid of, but I suppose as long as it works then that's great. Thanks again!