+ Start a Discussion
Br1Br1 

Dynamic APEX form

I don't know it is possible , but here we goes:

I want to build a form to edit a Standard Object, into a custom visualforce page.

To do that , i get the description of every field (with the getDescribe() and things like this), and i put it on a list.

The apex code:

Code:
The class:

 public class AccountEditableField {
  public String label { get; set;}
  public Schema.SObjectField value { get; set; }
 }

The Parser:

 public void accountDescribe(){
 
  Set <String> fieldKeys = new Set<String>();
   
  fieldKeys = AccountFieldsDescribe.keySet();
 
  List <String> editableFieldKeys =  new List<String>();
 
  String queryFields = '';
 
  for(String elem:fieldKeys){
   // Get the fields
   Schema.DescribeFieldResult field = (AccountFieldsDescribe.get(elem)).getDescribe();
    
   //Schema.DescribeFieldResult f = Schema.sObjectType.Account.fields.elem;
   if(field.isAccessible() && field.isUpdateable()){
    editableFieldKeys.add(elem);
    queryFields += field.getSObjectField()+', ';    
   }
       
   System.Debug(' ** \n'+AccountFieldsDescribe.get(elem)+'\n ** \n The field is visible (accesible)—:'+field.isAccessible()+' \n **  \n The field is Updateable–:'+field.isUpdateable());   
  }
   
  queryFields = queryFields.substring(0,queryFields.length() - 2);
    
 
  for(String f:editableFieldKeys){
   
   AccountEditableField fieldEditable = new AccountEditableField();
   Schema.DescribeFieldResult fieldDescribed = (AccountFieldsDescribe.get(f)).getDescribe();
   
   fieldEditable.label = fieldDescribed.getLabel();
   fieldEditable.value = fieldDescribed.getSObjectField();
   
   listOfFields.add(fieldEditable);
 
  }
 
 }

 



And try to generate the form at at the visualforce page:

Code:
 <apex:form id="accountEdition">
   <apex:repeat value="{!listOfFields}" var="field">
    <apex:outputText value="{!field.label}" />
    <apex:inputField value="{!field.value}" />
   </apex:repeat>
 </apex:form> 

 When i try to save the page, the error are:

Save error: Could not resolve the entity from <apex:inputField> value binding '{!field.value}'.  inputField can only be used with SObject fields

I know that the code at the apex controller can be simplified but i keep it in that way to make it easy to understand.

Anybody knows a workaround for that problem ?
Another way to build a dynamic form ?


Thanks in advance ;)


Message Edited by Br1 on 11-05-2008 12:15 PM
mikefmikef
What business case are you trying to solve?
If you are just creating a form with limited fields to edit an account, there is a way easier way of doing this.

Please state your business case you are trying to solve here, it will help frame a response.
Br1Br1
Hey mikef, thanks for the response.
The reason why i need a dynamic form, is because i'm trying to re-create a standard edition ( the one that works with '{RecordId}/e' ) into a visualforce page.
I have to reproduce the same edition form, but in a visualforce page without headers, sidebars or force styles, to make the form fit into a smaller screen.
I already have done the 'Customization' of the object detail view, parsing the result of the tag <apex:detail />  , but i dont have a tag that leaves a edition pageblock alone into a custom visualforce page.

Sorry about my english im not a native speaker, i hope you can understand what i'm trying to do.

Brx.
mikefmikef
Okay I am not sure I follow exactly what you are doing but to strip all the css out of a Visualforce page you can use apex page attributes.

Try this.

Code:
<apex:page controller="myController" sidebar="false" showHeader="false" standardStylesheets="false">
<apex:form id="accountEdition">
<apex:repeat value="{!listOfFields}" var="field">
<apex:inputField value="{!field.fieldName}" />
</apex:repeat>
</apex:form>
</apex:page>

 Now for the binding issue.
You have the wrapper class but there is no sobject in the class to bind to the page.
Something like this.
Code:
 public class AccountEditableField {
  private String fieldName;
  private Account acc;

  public AccountEditableField(String fieldName){
      setFieldName(fieldName);//write a setter for this
      setAcc(new Account());
  }

  public void setAcc(Account acc){
    this.acc = acc;
  }
  public Object getFieldName(){
    Object field = this.acc.get(this.fieldName);
    return field;
  }
 }

The Parser:

 public void accountDescribe(){
 
  Set <String> fieldKeys = new Set<String>();
   
  fieldKeys = AccountFieldsDescribe.keySet();
 
  List <String> editableFieldKeys =  new List<String>();
 
  String queryFields = '';
 
  for(String elem:fieldKeys){
   // Get the fields
   Schema.DescribeFieldResult field = (AccountFieldsDescribe.get(elem)).getDescribe();
    
   //Schema.DescribeFieldResult f = Schema.sObjectType.Account.fields.elem;
   if(field.isAccessible() && field.isUpdateable()){
    editableFieldKeys.add(elem);
    queryFields += field.getSObjectField()+', ';    
   }
       
   System.Debug(' ** \n'+AccountFieldsDescribe.get(elem)+'\n ** \n The field is visible (accesible)—:'+field.isAccessible()+' \n **  \n The field is Updateable–:'+field.isUpdateable());   
  }
   
  queryFields = queryFields.substring(0,queryFields.length() - 2);
    
 
  for(String f:editableFieldKeys){
   
   AccountEditableField fieldEditable;
   Schema.DescribeFieldResult fieldDescribed = (AccountFieldsDescribe.get(f)).getDescribe();
   
   fieldEditable = new AccountEditableField(fieldEditable.getName());
   
   listOfFields.add(fieldEditable);
 
  }
 
 }

 
Check out the sobject methods on get() that is were I came up with this solution.

I am not sure it will work, but it's a start.





Message Edited by mikef on 11-05-2008 09:47 AM
Br1Br1
A lot of thanks , i appreciate your collaboration , i will try with the SObject type, is a good idea.
stay tuned! :)
Br1Br1
well , the error message still showing up, but i think i'm on the right way..

this is what i have done at the moment, based on the help that mikef give to me about the sobject methods.

The page:
Code:
<apex:page sidebar="false" showHeader="false" controller="AccountEditController" standardStylesheets="false" >
 <apex:form>
  <apex:repeat value="{!listOfFields}" var="field">
            <apex:inputField value="{!field.sobjfield}" />   
    </apex:repeat>
 </apex:form>
</apex:page>

 The Controller:

Code:
public class AccountEditController {
 
 Map<String, Schema.SObjectField> AccountFieldsDescribe = new Map<String, Schema.SObjectField>();
 
 public AccountEditController (){
  
  Schema.DescribeSObjectResult AccountDescribe = Account.SObjectType.getDescribe();
  
  AccountFieldsDescribe = SObjectType.Account.fields.getMap();
 
  accountDescribe();
 }
 
 List<AccountEditableField> listOfFields = new List<AccountEditableField>();
 
 public List<AccountEditableField> getListOfFields(){
  return listOfFields;
 }
 
 public void accountDescribe(){
  
  Set <String> fieldKeys = new Set<String>();
   
  fieldKeys = AccountFieldsDescribe.keySet();
  
  List <String> editableFieldKeys =  new List<String>();
  
  String queryFields = '';
  
  for(String elem:fieldKeys){
   // Get the fields
   Schema.DescribeFieldResult field = (AccountFieldsDescribe.get(elem)).getDescribe();
    
   // Check if the fields can be viewed and updated.
   if(field.isAccessible() && field.isUpdateable()){
    // Add it to the list of editable field names, And build the list of fields to the dynamic query..
    editableFieldKeys.add(elem);
    queryFields += field.getSObjectField()+', ';    
   }    
      
  }
   
  queryFields = queryFields.substring(0,queryFields.length() - 2);
    
  // The dynamic query: 
  String queryString = 'Select '+ queryFields +' from Account where id = \''+System.currentPageReference().getParameters().get('id')+'\' limit 1'; 
  
  // Query for the account
  Account selectedAccount = Database.query(queryString);
  
  // Build the list to generate the form
  for(String f:editableFieldKeys){   
    
   Schema.DescribeFieldResult  sf = (AccountFieldsDescribe.get(f)).getDescribe();       
   AccountEditableField fieldEditable = new AccountEditableField(sf.getController(), selectedAccount);   
   listOfFields.add(fieldEditable);
   System.Debug('///////////////////////////////// ** \n Field Added: '+fieldEditable);
  }
  
 }
 
 public class AccountEditableField {
  
    private Schema.SObjectField fieldName;
    private Account acc;
  
    public AccountEditableField(Schema.SObjectField fieldName, Account sAcc){
        setAcc(sAcc);
        setFieldName(fieldName);         
    }
  
    public void setAcc(Account sAcc){
      this.acc = sAcc;
    }
    
    public Object getSobjfield(){
           
      Object field = this.acc.get(this.fieldName);
      return field;
    }
    
    public void setFieldName(Schema.SObjectField fieldtoset){
     this.fieldName = fieldtoset;
    }
    
 }
 
}

 Its a little bit different from the code proposed , and the steps are commented , to make it easy .
The binding problems still there, i need another point of view...

Thanks
Br1


SuzanyuSuzanyu

Hi Br1,

 

Did you get rid of the error. I have same error information to get object.field on the page. Can you give me some idea about your dynamic form. Thanks

 

That will be great for my dynamic stuff.

 

 

 

Sue 

Br1Br1

Hi Sue, bad news on that, i have't found a solution :(.

 

Now i'm thinking about it and a solution that comes to my mind is build a simple html form , with a method that based on the type of field creates the needed form tag and adds it to a list of strings, that can be placed with a repeater at the visualforce page.

 

This post is from a time ago and i doesn't remember clearly what i can get from a field, but i will give it a try. 

 

Try to reproduce my code and i give you some help with the other part of the idea , what do you think?

 

Br1

SuzanyuSuzanyu

Hi Bri,

 

Thanks for your response. I know the 'field' actually got from the code above not fieldobject -- that is the record field value.(there is no way to dynamically generate fieldojbect in force.com). So my final desicion on that may be the javascript in scontrol but which is quite hard to get the same look with salesforce like the date picker, even I can have dropdown/checkbox whatever I need.

 

 

Thanks

 

 

Sue

 

Br1Br1

I thought it and the other fields (like lookups) are hard to reproduce like you said.

 

We are in the same point, doing a lot of stuff to get the form that don't cover all the possibilities...

 

If you want the datepicker you can copy the js of a working datepicker field, and include library.js at the page to use the js methods of the calendar.

 

Br1

 

 

 

 

 

SuzanyuSuzanyu

Thank you so much for your information.

 

good luck

Raymond ZhuRaymond Zhu

Hi,

 

Now this problem could be solved. This is just for a mark because it really takes a lot of time to figure it out.

 

<apex:inputField value="{!Account[apiname of the field]}" styleClass="required website_required"/>