1

Apex Class :

public class AutoCompleteV2_Con {

    public String labelFieldVar{ get; set; }
    public String valueFieldVar{ get; set; }
    public String sObjVal{get;set;}
    public Integer randomJsIden{get;set;}
    public Object cacheField{get;private set;} 

    private Object targetFieldVar;

    public AutoCompleteV2_Con(){
        randomJsIden = getRandomNumber(1000000);
    }

   /*
    *Random number generator to change the js function name if multiple components us
    ***/
    private Integer getRandomNumber(Integer size){
        Double d = Math.random() * size;
        return d.intValue();
    }

    /*
    *This method queries data according to the passed parameters
    ***/
    @RemoteAction
    public static List<AutoCompleteData> getData(String sObjVal,String labelFieldVar,String valueFieldVar,String param){

        List<AutoCompleteData> AutoCompleteDatas = new List<AutoCompleteData>();
        param = String.escapeSingleQuotes(param);
        for( Sobject sObj : Database.query('SELECT '+labelFieldVar+' FROM '+sObjVal+' WHERE '+labelFieldVar+' LIKE \'%'+param+'%\'')){
            AutoCompleteDatas.add(new AutoCompleteData(sObj.get(valueFieldVar),sObj.get(labelFieldVar)));

        }

        return AutoCompleteDatas;

    }

    public class AutoCompleteData{
        public String id;
        public String text;

        public AutoCompleteData(Object id, Object text){
            this.id = String.valueOf(id);
            this.text = String.valueOf(text);
        }
    }


}

Visualforce Component :

<apex:component controller="AutoCompleteV2_Con" selfClosing="true">
    <apex:attribute name="SObject" description="SOQL Object to query"
        type="String" assignTo="{!sObjVal}" required="true" />
    <apex:attribute name="labelField"
        description="API Name of Field to display for label" type="String"
        required="true" assignTo="{!labelFieldVar}"/>
    <apex:attribute name="valueField"
        description="API Name of Field to display for value that is passed to the targetField"
        type="String" required="true" assignTo="{!valueFieldVar}"/>
    <apex:attribute name="targetField"
        description="Field of current object that will hold the selection."
        type="Object" assignTo="{!targetFieldVar}"/>
    <apex:attribute name="inputFieldId"
        description="Id of the field where the value will copied[Not generally required, used when you need to copy value to a field using js]"
        type="String" />
     <apex:attribute name="importJquery"
        description="Assign false if you dont want to jquery files"
        type="Boolean" default="true" />
    <apex:attribute name="syncManualEntry"
        description="Allow manual entry of data from autocomplete component."
        type="Boolean" default="true" />
    <apex:attribute name="allowClear" description="Set true to give user a option to clear existing value" type="Boolean" default="true"/>

    <apex:attribute name="Style" description="style for the input component" type="String"/>
    <!--Required js files-->
    <apex:outputPanel rendered="{!importJquery}">
        <apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"/>
    </apex:outputPanel>
        <apex:includeScript value="{!URLFOR($Resource.select2, 'select2-3.4.2/select2.js')}"/>
        <apex:stylesheet value="{!URLFOR($Resource.select2, 'select2-3.4.2/select2.css')}"/>
    <script>
        var v2{!randomJsIden}

        var prevVal{!randomJsIden};
        function autocompleteV2{!randomJsIden}(){
             var v2=this;
             jQuery(function($){ //on document.ready
                    v2.init($)
             });
        }

        autocompleteV2{!randomJsIden}.prototype={
            init : function($){

                       var $elem = $( ".auto{!randomJsIden}" ).select2({
                           minimumInputLength: 1,
                           placeholder: "No value selected",
                           allowClear : {!allowClear},
                           query: function (query) {
                               queryData{!randomJsIden}(query);

                           },
                           createSearchChoice:function(term, data) {
                                if({!syncManualEntry} == true){
                                    return {id:term, text:term};
                                }
                            }
                       });

                       $elem.on("select2-selecting", function(e) {

                           $('.hiddenField{!randomJsIden}').val(e.val);
                       });

                       $elem.on("select2-removed", function(e) {
                           $('.hiddenField{!randomJsIden}').val('');
                       });



                       if('{!cacheField}' !=''){
                           $elem.select2("data", {id: "{!targetFieldVar}", text: "{!cacheField}"})  
                       }  

                    },

            triggerSearch :function(val){

                                if(prevVal{!randomJsIden} != val){
                                    $=jQuery;
                                    prevVal{!randomJsIden} = val;
                                    var select = $('input.auto{!randomJsIden}');          
                                    var search = $('.select2-input')
                                    select.select2('open');
                                    search.val(val);

                                    search.trigger("input");
                                }
                            }
        }





         /*
        *This method queries data according to the passed parameter
        *and populates the combobox accordingly
        ***/    
        function queryData{!randomJsIden}(query){

           Visualforce.remoting.Manager.invokeAction(
                     '{!$RemoteAction.AutoCompleteV2_Con.getData}','{!sObjVal}','{!labelFieldVar}','{!valueFieldVar}',query.term,
                     function(result, event){

                         //if success
                         if(event.status){ 
                             var data = {results: []}
                             data.results = result;                            
                             query.callback( data);                           
                         }
                         else{
                              alert('Invalid Field/Object API Name : '+event.message);
                         }

                     }, 
                      {escape: true}
                );
            }  


    </script>

    <apex:inputText style="{!Style}" styleClass="auto{!randomJsIden}" value="{!cacheField}" />

    <apex:outputPanel id="hiddenPanel">
        <apex:inputText value="{!targetField}" id="hiddenField"
            styleClass="hiddenField{!randomJsIden}" style="display:none"/>
    </apex:outputPanel>
    <script>v2{!randomJsIden} = new autocompleteV2{!randomJsIden}({});</script>
</apex:component>

Error coming from point :

for( Sobject sObj : Database.query('SELECT '+labelFieldVar+' FROM '+sObjVal+' WHERE '+labelFieldVar+' LIKE \'%'+param+'%\'')){
            AutoCompleteDatas.add(new AutoCompleteData(sObj.get(valueFieldVar),sObj.get(labelFieldVar)));

        }

        return AutoCompleteDatas;

Input :

<c:AutoCompleteV2 allowClear="true" importJquery="true" labelField="client_p_n__c" SObject="Quote_Line_Item__c" valuefield="client_p_n__c" targetField="{!inputText10}" style="width:200px"/>

This is a Autocomponent v2 free app (http://blogforce9.blogspot.in/2013/10/auto-complete-visualforce-component-v2.html).I tried many possible ways to restrict autocompletedatas from restrict the duplicates .again and again i am getting same working since no luck till now.then i tried with jquery to restrict data from visual force component side .it is very badly acting when i work with component side .then i came back to work with controller side .

Problem is ,when i search on my autocomplete input text like "Ales" it is showing multiple times, since this field value is recorded in many records . I want to show that value only once in autocompletion even though it has recorded in many records.

Let me know if i am unclear with my question .Thanks in advance.

1 Answer 1

1

I am surprised you found an app with so many security vulnerabilities. You have several injection issues. First thing you should do is rewrite the method to eliminate these. I would take advantage of strong types in my approach:

public List<AutoCompleteData> getData
    (SObjectType sObjectType, SObjectField labelField,
    SObjectField valueField, String fuzzyValue)
{
    List<AutoCompleteData> data = new List<AutoCompleteData>();
    fuzzyValue = '%' + fuzzyValue + '%';
    String fields = String.join(', ' new List<String>
    {
        String.valueOf(labelField), String.valueOf(valueField)
    });
    for (SObject record : Database.query(
        'SELECT ' + field + ' FROM ' + sObjectType +
        ' WHERE ' + labelField + ' LIKE : fuzzyValue'
    )) data.add(new AutoCompleteData(
        (String)record.get(valueField), (String)record.get(labelField)
    );
}

Since you're not even querying for the valueFieldVar, you must be using Id. It is unclear how you want to handle collisions, but if you actually just want to use the value and not the Id, it is pretty straightforward. Just use a set.

Set<String> values = new Set<String>();
for (SObject record : Database.query(/*query*/)) values.add((String)record.get(field));
List<AutoCompleteData> data = new List<AutoCompleteData>();
for (String value : values) data.add(new AutoCompleteData(value, value));

You must log in to answer this question.

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