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
Rafael.Martins.SantosRafael.Martins.Santos 

Optimizing code - APEX - Javascript - Visualforce Page

Hi All,
I'm trying optimize my code, so I need help.
Let me explain first how works my code.

I have a table in my page that brings a list of accounts with your fields.
Each of these fields is a field of type Choice List, and when I select an option the account are updated.
Here is the image of my table:
User-added image

The only way I could update the field is creating for each column a function in Javascript and a Method in APEX.
Javascrit:
function gravar(id, status){
     var id_conta = id;
     var nome = document.getElementById(status).value;
     executar(id_conta, nome);
    }

Apex:
        public pageReference Save(){
            System.debug('Executou ');
            id_conta = System.currentPageReference().getParameters().get('id_contas');
            status_conta = System.currentPageReference().getParameters().get('suporte_status');
            
            for(Account conta : [SELECT Id, Name, ServiceNow_Status__c, Suporte_Status__c, Adm_Status__c, BS_BH_Status__c FROM Account                                             WHERE Id =: id_conta]){
                conta.Suporte_Status__c = status_conta;
                update conta;
            }

           return null;
        }

The problems is, if I have 45 columns I must create 45 funcions and Apex Methods.
I want create only 1 Function and only 1 Method that Allow to me update the field.
The process will update each field at a time.

Can someone help me to optimize my code?

Thanks
Rafael.
 
Best Answer chosen by Rafael.Martins.Santos
Asif Ali MAsif Ali M
Here is the code. You just need to add couple of IF blocks for other data types (DATETIME, NUMBER..etc)
public pageReference Save(){

// campo_conta = Label Name
// status_conta = Field Value
// id_conta = AccounId


// Get the params values
    id_conta = System.currentPageReference().getParameters().get('id_conta');
    status_conta = System.currentPageReference().getParameters().get('status_conta');
    campo_conta = System.currentPageReference().getParameters().get('campo_conta');


// Generate the Lable-Field Map
    Map<String, Schema.SObjectField> fields = Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap();
    Map<String, Schema.SObjectField> labelMap = new Map<String, Schema.SObjectField>();
    for (String key: fields.keySet()) {
        labelMap.put(fields.get(key).getDescribe().getLabel(), fields.get(key));
    }

// Get the Data Type of the Field
    Schema.DisplayType dataType = labelMap.get(campo_conta).getDescribe().getType();
    string fieldName = labelMap.get(campo_conta).getDescribe().getName();


// Only string binding works in Dynamic SOQL
    String soqlQuery = 'SELECT :fieldName FROM Account WHERE Id =:id_conta';
// Replace the :fieldName with Field API Name
    soqlQuery = soqlQuery.replace(':fieldName', fieldName);
    Account accounts = new List<Account>();
    accounts = Database.query(soqlQuery);


    for (Account conta : accounts) {
// ADD additional IF block for other DATA TYPES
        if (dataType == Schema.DisplayType.DATE) {
            conta.put(fieldName, Date.valueOf(status_conta));
        }
        if (dataType == Schema.DisplayType.BOOLEAN) {
            conta.put(fieldName, Boolean.valueOf(status_conta));
        }
    }

    update accounts;
    return null;
}



 

All Answers

James BoggsJames Boggs
It would be helpful to see your Visualforce markup as well, since I'm not sure I understand the problem. Is there any reason that you can't use a standard set controller for your table?
Rafael.Martins.SantosRafael.Martins.Santos
Oh Sorry,
Here is my Visualforce code

<apex:page showHeader="false" sidebar="false" standardStylesheets="false"
applyHtmlTag="false" applyBodyTag="false" docType="html-5.0" controller="Account_Mancha">
        <apex:outputPanel id="page">       
<table>
        <apex:form >

        <apex:actionFunction name="executar" action="{!Save}" reRender="null">
          <apex:param name="id_contas" value="" assignTo="{!id_conta}"/>
          <apex:param name="suporte_status" value="" assignTo="{!status_conta}"/>
          <apex:actionSupport action="{!Save}" event="oncomplete" rerender="page"/>
        </apex:actionFunction>

            <apex:repeat value="{!TodasContas}" var="conta">
                  <tr>
                        <td><apex:outputLink value="/{!conta.Id}" >{!conta.Name}</apex:outputLink></td>
                        <td ><apex:inputField value="{!conta.Suporte_Status__c}" id="suporte" onchange="gravar('{!conta.Id}', '{!$Component.suporte}');" >                                  </apex:inputField>
                        </td>
                  </tr>
             </apex:repeat>
            </apex:form>
        </table>
</apex:outputPanel>   
</apex:page>

 
James BoggsJames Boggs
Can you also post your entire Apex controller as well, not just the Save method?
Rafael.Martins.SantosRafael.Martins.Santos
Here My All Code:
APEX:

public class Account_Mancha {
    
    public String id_conta{get;set;}
    public String status_conta{get;set;}
    public String campo_conta{get;set;}
    public String status_adm{get;set;}
    public String status_bs{get;set;}
    public String status_servicenow{get;set;}
    public String usuarioId{get;set;}
    public String filtro{get;set;}
    
      public Account_Mancha(){
          
             filtro = '';
               //usuarioId = UserInfo.getUserId();
               usuarioId= '';
      }
    
        public void GetContas() {
            List<Account> contas = [SELECT Id, Name, OwnerId, ServiceNow_Status__c, Suporte_Status__c, Adm_Status__c, BS_BH_Status__c  FROM Account WHERE OwnerId = : usuarioId ORDER BY Name LIMIT 100];
        }

        public List<Account> getTodasContas(){
            List<Account> contas = [SELECT Id, Name, OwnerId, ServiceNow_Status__c, Suporte_Status__c, Adm_Status__c, BS_BH_Status__c  FROM Account WHERE OwnerId = : usuarioId ORDER BY Name LIMIT 100];
            return contas;
        }
    
        public List<SelectOption> getListOfUser(){
               List<User> Users = [select id ,Username, Regional__c, name, IsActive from user WHERE IsActive = true] ;
               List<SelectOption> UserOptionList = new List<SelectOption>();
               UserOptionList.add(new SelectOption( ' ' ,'--- Selecione um usuário ---'));
               for(User u : Users ){
                   UserOptionList.add(new SelectOption(u.Id , u.Name));
               }
              return UserOptionList ;
        }
    
        public pageReference Save(){
            System.debug('Executou ');
            id_conta = System.currentPageReference().getParameters().get('id_contas');
            status_conta = System.currentPageReference().getParameters().get('suporte_status');
            
            for(Account conta : [SELECT Id, Name, ServiceNow_Status__c, Suporte_Status__c, Adm_Status__c, BS_BH_Status__c FROM Account WHERE Id =: id_conta]){
                conta.Suporte_Status__c = status_conta;
                update conta;
            }
           return null;
        }
    
    public pageReference Save1(){
            System.debug('Executou ');
            id_conta = System.currentPageReference().getParameters().get('id_contas');
            status_conta = System.currentPageReference().getParameters().get('suporte_status');

            for(Account conta : [SELECT Id, Name, ServiceNow_Status__c, Suporte_Status__c, Adm_Status__c, BS_BH_Status__c FROM Account WHERE Id = : id_conta]){
                conta.Adm_Status__c = status_adm;
                update conta;
            }
            return null;
        }
    
    public pageReference Save2(){
            System.debug('Executou');
            id_conta = System.currentPageReference().getParameters().get('id_contas');
            status_conta = System.currentPageReference().getParameters().get('suporte_status');

            for(Account conta : [SELECT Id, Name, ServiceNow_Status__c, Suporte_Status__c, Adm_Status__c, BS_BH_Status__c FROM Account WHERE Id =: id_conta]){
                conta.BS_BH_Status__c = status_bs;
                update conta;
            }
            return null;
        }
    
    public pageReference Save3(){
            System.debug('Executou ');
            id_conta = System.currentPageReference().getParameters().get('id_contas');
            status_conta = System.currentPageReference().getParameters().get('suporte_status');

            for(Account conta : [SELECT Id, Name, ServiceNow_Status__c, Suporte_Status__c, Adm_Status__c, BS_BH_Status__c FROM Account WHERE Id =: id_conta]){
                conta.ServiceNow_Status__c = status_servicenow;
                update conta;
            }
            return null;
        }
}


Javascript Code:
function gravar(id, status){
     var id_conta = id;
     var nome = document.getElementById(status).value;
     executar(id_conta, nome);
    }
    
    function gravar1(id, status){
     var id_conta = id;
     var nome = document.getElementById(status).value;
     executar_adm(id_conta, nome);
    }
    
    function gravar2(id, status){
     var id_conta = id;
     var nome = document.getElementById(status).value;
     executar_bs(id_conta, nome);
    }
    
    function gravar3(id, status){
     var id_conta = id;
     var nome = document.getElementById(status).value;
     executar_sn(id_conta, nome);
    }


Visualforce:

<apex:page showHeader="false" sidebar="false" standardStylesheets="false"
applyHtmlTag="false" applyBodyTag="false" docType="html-5.0" controller="Account_Mancha">
    <apex:stylesheet value="{!URLFOR($Resource.css_mancha, 'css/estilo.css')}"/>
    <apex:includeScript value="{!URLFOR($Resource.mancha_js, 'js/funcao.js')}"/>
<html>
<head>
    <title>Mapa</title>   
</head>
<body>
<div id="container">
    <div id="header">
        <div class="bar_container">
            <apex:form >
            <ul>
            <li>
                <!--<apex:inputText value="{!usuarioId}">Pesquisar conta: </apex:inputText>-->
            </li>
                <li>
                    <apex:selectList value="{!usuarioId}" size="1" multiselect="false">
                     <apex:actionSupport event="onchange" action="{!GetContas}"/>
                     <apex:selectOptions value="{!ListOfUser}" />
                    </apex:selectList>
                </li>
                <li>
                    <apex:commandButton value="Filtrar" action="{!GetContas}"/>
                </li>
            </ul>
                </apex:form>
        </div>
    </div>
    
    <div id="content">
    <div class="painel">
        <h1>SERVICE IT - MAPA</h1>
        <apex:outputPanel id="page">
        <table>
        <apex:form >
        <apex:actionFunction name="executar" action="{!Save}" reRender="null">
          <apex:param name="id_contas" value="" assignTo="{!id_conta}"/>
          <apex:param name="suporte_status" value="" assignTo="{!status_conta}"/>
          <apex:actionSupport action="{!Save}" event="oncomplete" rerender="page"/>
        </apex:actionFunction>
        
        <apex:actionFunction name="executar_adm" action="{!Save1}" reRender="null">
          <apex:param name="id_contas" value="" assignTo="{!id_conta}"/>
          <apex:param name="adm_status" value="" assignTo="{!status_adm}"/>
            <apex:actionSupport action="{!Save1}" event="oncomplete" rerender="page"/>
        </apex:actionFunction>
        
        <apex:actionFunction name="executar_bs" action="{!Save2}" reRender="null">
          <apex:param name="id_contas" value="" assignTo="{!id_conta}"/>
          <apex:param name="bs_status" value="" assignTo="{!status_bs}"/>
            <apex:actionSupport action="{!Save2}" event="oncomplete" rerender="page"/>
        </apex:actionFunction>
        
        <apex:actionFunction name="executar_sn" action="{!Save3}" reRender="null">
          <apex:param name="id_contas" value="" assignTo="{!id_conta}"/>
          <apex:param name="sn_status" value="" assignTo="{!status_servicenow}"/>
            <apex:actionSupport action="{!Save3}" event="oncomplete" rerender="page"/>
        </apex:actionFunction>
            <tr>
                <th colspan="1" class="celula_em_branco"></th>
                <th colspan="4" class="celula_cinza_claro">MANAGED SERVICES</th>
            </tr>
            <tr>
                <td class="cor_cinza">Conta</td>
                <td class="cor_cinza ">Suporte</td>
                <td class="cor_cinza ">Adm</td>
                <td class="cor_cinza ">BS/BH</td>
                <td class="cor_cinza ">ServiceNow</td>
            </tr>
            <apex:repeat value="{!TodasContas}" var="conta">
            <tr>
            <td class="celula_cinza_claro" style="width: 5%;"><apex:outputLink value="/{!conta.Id}" >{!conta.Name}</apex:outputLink></td>
            <td >
                 <apex:inputField value="{!conta.Suporte_Status__c}" id="suporte" onchange="gravar('{!conta.Id}', '{!$Component.suporte}');" styleClass="inputField_custom"></apex:inputField>
             </td>
            <td>
                     <apex:inputField value="{!conta.Adm_Status__c}" id="adm" onchange="gravar1('{!conta.Id}', '{!$Component.adm}');" styleClass="inputField_custom" ></apex:inputField>
             </td>
            <td>
          <apex:inputField value="{!conta.BS_BH_Status__c}" id="bs" onchange="gravar2('{!conta.Id}', '{!$Component.bs}');" styleClass="inputField_custom"></apex:inputField>
         </td>
            <td>
                         
                 <apex:inputField value="{!conta.ServiceNow_Status__c}" id="sn" onchange="gravar3('{!conta.Id}', '{!$Component.sn}');" styleClass="inputField_custom"></apex:inputField>
             </td>
            </tr>
            </apex:repeat>
            </apex:form>
        </table>
            </apex:outputPanel>
    </div>
    </div>
    <div id='footer'>
        <div class="bar_container">
            <ul>
                <li>SERVICE IT</li>
            </ul>
        </div>
    </div>
</div>
</body>
</html>
</apex:page>
James BoggsJames Boggs
If I understand all this, which I'm not sure that I do, you can simplify quite a lot. Add a class variable: public List TodasContas; in your GetTodasContas method add TodasContas = contas; Just need one save method: public PageReference Save(){ update TodasContas; return null; } But that's really just a bandaid, I think you'd benefit from digging into the documentation: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_custom_list_controller.htm
Rafael.Martins.SantosRafael.Martins.Santos
Yes,
the point is that, I want use only one method and only one function.
The problem that I'm facing, is I can't update only one field at time using one function and one method.
I need find some way that the code could get the current Id, the current field and update the right field.
This code that I sent to you, works fine, but I want optimize him.
Asif Ali MAsif Ali M
You can optimize this into one method like below. Which expects recordId(can be multiple) and fieldName. Becuase the field can be Any type you need to add additional logic to do the type conversion as mentioned in the code comments.

Warning: Not tested the code. You may get syntax errors. 
 
public String recId{get;set;}
public String fieldName{get;set;}


public pageReference Save(){

recId = System.currentPageReference().getParameters().get('recId');
fieldName = System.currentPageReference().getParameters().get('fieldName');

String soqlQuery = 'SELECT :fieldName FROM Account WHERE Id =:recId';
soqlQuery = soqlQuery.replace(':fieldName', fieldName);

Account accounts = Database.query(soqlQuery);

for(Account conta : accounts ){
// This will only work for String types. If there are other Types then you need to add if block for each type and do the Type conversion manually like conta.put(fieldName, Date.ValueOf(status_conta));    

conta.put(fieldName, status_conta);

}

update accounts;
return null;
}


 
Asif Ali MAsif Ali M
Please change the soqlQuery to below one because in Dynamic SOQL bind variables are not accepted. Convert the list of ID into comma seperated  String
 
// recIdString should be like ('id1', 'id2', 'id3') (including the parenthesis) 
String soqlQuery = 'SELECT :fieldName FROM Account WHERE Id in ' + recIdString;

 
Rafael.Martins.SantosRafael.Martins.Santos
Hi Asif,

Thanks for your help.
I did like this and work:

I have now 3 parameters:

        <apex:actionFunction name="executar" action="{!Save}" reRender="null">
          <apex:param name="id_contas" value="" assignTo="{!id_conta}"/>
          <apex:param name="status" value="" assignTo="{!status_conta}"/>
          <apex:param name="nome_campo" value="" assignTo="{!campo_conta}"/>

          <apex:actionSupport action="{!Save}" event="oncomplete" rerender="page"/>
        </apex:actionFunction>

And in Apex I did like this
String suport = Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap().get('Suporte_Status__c').getDescribe().getLabel();
if(suport == campo_conta){
                    System.debug('Suporte: '+suport +', Campo Conta: '+campo_conta);
                    conta.Suporte_Status__c = status_conta;
                    update conta;
  }

So I get the Name of the field that are updating and verify in APEX which is the field that are updating and execute that condition.

Now I have only one function and only one method to save all.
But I have one more problem. If I use the Schema like I'm using, I will have to repeat the Schema 45 times. So do you know some way to search for the fields automatically using Schema?

Thanks
Rafael
 
Asif Ali MAsif Ali M
Your code will not work even if you have a if for each field because you are simply assigning the value to it without converting to it. Because you are getting the value from Queryy String, which is always String type,  you need to explicitly convert the value to Field Type. Check the below updated code which has If blocks for Data Types. You need to add few more if block for other Data Types.
public String recId{get;set;}
public String fieldName{get;set;}

public pageReference Save(){

recId = System.currentPageReference().getParameters().get('recId');
fieldName = System.currentPageReference().getParameters().get('fieldName');
// ADDED NEW LINE HERE
Schema.DisplayType dataType = Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap().get(fieldName).getDescribe().getType();


// recIdString should be like ('id1', 'id2', 'id3') (including the parenthesis)
String soqlQuery = 'SELECT :fieldName FROM Account WHERE Id in ' + recIdString
soqlQuery = soqlQuery.replace(':fieldName', fieldName);

Account accounts = Database.query(soqlQuery);

for(Account conta : accounts ){
// This will only work for String types. If there are other Types then you need to add if block for each type and do the Type conversion manually like conta.put(fieldName, Date.ValueOf(status_conta));    

&nbsp;   // ADD additional IF block for other DATA TYPES
    if(dataType == Schema.DisplayType.DATE) {
        conta.put(fieldName, Date.valueOf(status_conta));
    }
    if(dataType == Schema.DisplayType.BOOLEAN) {
        conta.put(fieldName, Boolean.valueOf(status_conta)); 
    }
}

update accounts;
return null;
}

 
Asif Ali MAsif Ali M
Hi Rafael,
I am sorry. I overlooked your message.  Ignore my previous code. 
Let me understand your params first. 
status_conta = Fiedname?
campo_conta = Label of the Field?
 
Rafael.Martins.SantosRafael.Martins.Santos
Hi Asif,
No problem.
Yes, in the status_conta I'm getting the field value, and the campo_conta is getting the label of the field.
So I create a IF condition that check the label of the field that will be updated.
For now, it's working. But I think I will not need use the Schema, because I already getting the label value from the page. So I will have 45 different fields, and I must create a If for each field, and as I Know the exactly name of the field, I can compare like the example below.
if('Label_Field' == campo_conta){
// Do something here
}
Asif Ali MAsif Ali M
Hi Rafael,

Are you performing any additional logic other than just updating the field with label ? If not you can go with Schema to dynamically update field and You also do not need thrid parameter Label. Just pass the fieldName and value.

 
Rafael.Martins.SantosRafael.Martins.Santos
Yes, I only will update the field.
Other logic that I will use is to filter the list.

Do you can share with me a example of how I can do that?

because I update the field just selecting another options, without clicking in some button, and until now, I can't make it work without a If condition.
Rafael.Martins.SantosRafael.Martins.Santos
I have 3 parameters, because I get the Account Id, the value of the field and the label of the field.
 
Asif Ali MAsif Ali M
Here is the code. You just need to add couple of IF blocks for other data types (DATETIME, NUMBER..etc)
public pageReference Save(){

// campo_conta = Label Name
// status_conta = Field Value
// id_conta = AccounId


// Get the params values
    id_conta = System.currentPageReference().getParameters().get('id_conta');
    status_conta = System.currentPageReference().getParameters().get('status_conta');
    campo_conta = System.currentPageReference().getParameters().get('campo_conta');


// Generate the Lable-Field Map
    Map<String, Schema.SObjectField> fields = Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap();
    Map<String, Schema.SObjectField> labelMap = new Map<String, Schema.SObjectField>();
    for (String key: fields.keySet()) {
        labelMap.put(fields.get(key).getDescribe().getLabel(), fields.get(key));
    }

// Get the Data Type of the Field
    Schema.DisplayType dataType = labelMap.get(campo_conta).getDescribe().getType();
    string fieldName = labelMap.get(campo_conta).getDescribe().getName();


// Only string binding works in Dynamic SOQL
    String soqlQuery = 'SELECT :fieldName FROM Account WHERE Id =:id_conta';
// Replace the :fieldName with Field API Name
    soqlQuery = soqlQuery.replace(':fieldName', fieldName);
    Account accounts = new List<Account>();
    accounts = Database.query(soqlQuery);


    for (Account conta : accounts) {
// ADD additional IF block for other DATA TYPES
        if (dataType == Schema.DisplayType.DATE) {
            conta.put(fieldName, Date.valueOf(status_conta));
        }
        if (dataType == Schema.DisplayType.BOOLEAN) {
            conta.put(fieldName, Boolean.valueOf(status_conta));
        }
    }

    update accounts;
    return null;
}



 
This was selected as the best answer
Rafael.Martins.SantosRafael.Martins.Santos
Hi Asif,
Occurred an error:
Attempt to de-reference a null object
There is an expression error '{!Save}' in page mancha: Class.Account_Mancha.Save: line 96, column 1

The code line is this:

// Get the Data Type of the Field
   LINE 96 -->  Schema.DisplayType dataType = labelMap.get(campo_conta).getDescribe().getType();
    string fieldName = labelMap.get(campo_conta).getDescribe().getName();
Asif Ali MAsif Ali M
MAP keys are case sensitive. make sure the value is campo_conta is having same CASE as defined on the Object. 
Rafael.Martins.SantosRafael.Martins.Santos
Hi Asif,

After I made some change in the code, my page works.
Thanks for your help.

Best Regards
Rafael