• AllenMann
  • NEWBIE
  • 0 Points
  • Member since 2015
  • Wed Systems Developer
  • HCSS

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 1
    Questions
  • 3
    Replies
I am using chapter 3 in Salesforce Knowledge Developer Guide Version 34.0, Summer ’15 (https://resources.docs.salesforce.com/sfdc/pdf/salesforce_knowledge_dev_guide.pdf)
as a starting point to build a Knowledge search page.

> Our data category hierarchy is: Topics > Product Name > Tabs in Product

I want the top part of the page to show the typical search results and a bottom table that shows related articles according the data category "Topics". 

Has anyone tried anything like this? Have any suggestions? I am new to VF and Apex so any help would be immensely appreciated.
 
VF Page: 
<apex:page controller="VfSearchController" sidebar="false" title="Knowledge Search">
<style>
 td{
  vertical-align : top;   
  text-align: left;
 }
</style>
<apex:form >
 <apex:panelGrid columns="2" >
  <apex:panelGroup >
   <apex:pageBlock >
    <apex:outputText value="Filter Your Results" />
     <apex:pageBlockSection columns="1">
      <apex:dataTable value="{!dataCategoryGroupInfo}" var="dataCategory" id="dataCategory">
       <apex:column width="20%">
        <apex:outputLabel for="categoryType_{!dataCategory.name}">{!dataCategory.name}</apex:outputLabel> 
        <br />
        <select id="categoryType_{!dataCategory.name}" name="categoryType_{!dataCategory.name}" onchange = "refreshSearchResult()" >
         <option value="NoFilter">No Filter</option>
         <option value="All">All</option>
         <knowledge:categoryList categoryVar="category" categoryGroup="{!dataCategory.name}" rootCategory="All" level="-1">
         <option value="{!category.name}">
          <apex:outputText escape="false" value="{!LPAD(' ',6*category.depth,'&nbsp;')}" />
          {!category.label}
         </option>
        </knowledge:categoryList>
        </select>
       </apex:column>
      </apex:dataTable>
     </apex:pageBlockSection>
    </apex:pageBlock>
    <apex:pageBlock >
    <apex:outputText value="Ralated Articles" />    
    <apex:pageBlockSection columns="1">
     <knowledge:articleList articleVar="article" articleTypes="Topics" pageSize="10" >
     <li>
      <apex:outputLink target="_blank" value="{!URLFOR($Action.KnowledgeArticle.View, article.id, ['popup' = 'true'])}">{!article.title}</apex:outputLink>
     </li>
     </knowledge:articleList>
    </apex:pageBlockSection>
   </apex:pageBlock>
 </apex:panelGroup>
 <apex:panelGroup >
  <apex:pageBlock title="Search" >
   <apex:inputText value="{!searchstring}" id="theSearchstring" maxlength="100" size="110"  onkeypress="if (event.keyCode == 13) {refreshSearchResult();return false;} "/> &nbsp;
   <apex:commandButton value="Go" id="submitButton" style="width:30" reRender="theSearchResults" />
  </apex:pageBlock>  
  <apex:messages />
  <apex:panelGroup id="theSearchResults" >
  <apex:pageBlock title="Search Results" > 
   <apex:panelGrid width="100%">
    <table width="99%">
     <tr>
      <th width="33%">Title</th>
      <th width="33%">Article Type</th>
      <th width="33%">Summary</th>
     </tr>
    </table>
    <knowledge:articleList articleVar="article"  categories="{!categoryKeyword}" Keyword="{!searchstring}" pageNumber="{!currentPageNumber}" hasMoreVar="false" pageSize="10">
    <table  width="99%">
     <tr>
      <td width="33%">
      <apex:outputLink target="_blank" value="{!URLFOR($Action.KnowledgeArticle.View, article.id,['popup' = 'true'])}">{!article.title}</apex:outputLink>
      </td>
      <td width="33%"><apex:outputText >{!article.articleTypeLabel}</apex:outputText></td>
      <td width="33%"><apex:outputText >{!article.abstract}</apex:outputText></td>
     </tr>
    </table>
    </knowledge:articleList>
  </apex:panelGrid> 
 </apex:pageBlock>
      
  <apex:panelGroup id="theRelatedArticles" >
  <apex:pageBlock title="Related Topics" > 
   <apex:panelGrid width="100%">
    <table width="99%">
     <tr>
      <th width="33%">Title</th>
      <th width="33%">Article Type123</th>
      <th width="33%">Summary</th>
     </tr>
    </table>
    <knowledge:categoryList categoryVar="category" categoryGroup="Topics" rootCategory="HeavyBid" level="-1">
        <option value="{!category.name}">{!category.label}</option>
    </knowledge:categoryList>
  </apex:panelGrid> 
 </apex:pageBlock>
      
      //Start Pagination      
 <apex:panelGrid columns="2">
   <apex:commandLink action="{!previous}" value="Previous" style="{!IF(prevRequired = true,'display:block','display:none')}" reRender="theSearchResults"/> 
   <apex:commandLink action="{!next}" value="Next"  style="{!IF(nextRequired = true,'display:block','display:none')}" reRender="theSearchResults"/>  
 </apex:panelGrid>
 </apex:panelGroup>
 </apex:panelGroup>
     </apex:panelGroup>
     </apex:panelGrid>
 <apex:actionFunction action="{!refreshSearchResult}" name="refreshSearchResult" rerender="theSearchResults" >
 </apex:actionFunction>
    
    


 </apex:form>
</apex:page>

Controller: 

 
public with sharing class VfSearchController{
    
    //Page Size
    private Static Final Integer PAGE_NUMBER = 10;
    
    //Search String used in ArticleList tag
    public String searchstring { get; set; }
    
    //Is new List reqd
    private boolean isRefRequired = true;
    
    //Exclude filter criteria for UI only
    private static final String EXCLUDE_CRITERIA_FILTER = 'All';
    
    //Keeps track of current page & max size of article list
    Integer currentPage = 1;
    Integer maxSize = 1;
    
    //Returns array of Category Groups
    public DataCategoryGroupInfo[] getDataCategoryGroupInfo() {
        return DataCategoryUtil.getInstance().getAllCategoryGroups();
    }
    
    //Returns category keyword required to filter articleList.
    public String getCategoryKeyword() {
        DataCategoryGroupInfo[] categoryGroups =
            DataCategoryUtil.getInstance().getAllCategoryGroups();
        
        String categoryCondition = '';
        for (DataCategoryGroupInfo categoryGroup : categoryGroups) {
            String selectedCategoryName =
                System.currentPageReference().getParameters().Get('categoryType_'+categoryGroup.getName());
            
            if(selectedCategoryName != null && !selectedCategoryName.equals('NoFilter')) {
                if(categoryCondition=='' && selectedCategoryName != null){
                    categoryCondition=categoryCondition+categoryGroup.getName() + ':' +
                        System.currentPageReference().getParameters().Get('categoryType_'+categoryGroup.getName());
                }else {
                    categoryCondition=categoryCondition + ',' +categoryGroup.getName() + ':' +
                        System.currentPageReference().getParameters().Get('categoryType_'+categoryGroup.getName());
                }
            }
        }
        
        String categoryFilter = '';
        for (DataCategoryGroupInfo categoryGroup : categoryGroups) {
            String categoryType =
                System.currentPageReference().getParameters().Get('categoryType_'+categoryGroup.getName());
            if(categoryType != null && !categoryType.equals('NoFilter')) {
                if(categoryFilter == ''){
                    categoryFilter = categoryGroup.getName() + '__c ABOVE_OR_BELOW ' + categoryType
                        +'__c';
                } else {
                    categoryFilter = categoryFilter + categoryGroup.getName() + categoryType;
                }
            }
        }
        try {
            if(categoryFilter.length()>0) {
                if(searchString != null && searchString.length() >0 ) {
                    String searchquery = 'FIND \'' + searchString + '*\'IN ALL FIELDS RETURNING KnowledgeArticleVersion(Id, title, UrlName, LastPublishedDate,LastModifiedById where PublishStatus =\'online\' and Language = \'en_US\') WITH DATA CATEGORY '+categoryFilter ;
                    List<List
                        <SObject>
                        >searchList = search.query(searchquery);
                    List
                        <KnowledgeArticleVersion>
                        articleList =
                        (List
                         <KnowledgeArticleVersion>
                        )searchList[0];
                    maxSize = articleList.size() ;
                    // maxSize = maxSize.divide(PAGE_NUMBER,2,System.RoundingMode.UP);
                } else {
                    String qryString = 'SELECT Id, title, UrlName, LastPublishedDate,LastModifiedById FROM KnowledgeArticleVersion WHERE (PublishStatus = \'online\' and Language = \'en_US\') WITH DATA CATEGORY '+categoryFilter;
                    List
                        <KnowledgeArticleVersion>
                        articleList= Database.query(qryString);
                    maxSize = articleList.size() ;
                    // maxSize = maxSize.divide(PAGE_NUMBER,2,System.RoundingMode.UP);
                }
            } else {
                String qryString = 'SELECT Id, title, UrlName, LastPublishedDate,LastModifiedById FROM KnowledgeArticleVersion WHERE (PublishStatus = \'online\' and Language = \'en_US\')';
                List
                    <KnowledgeArticleVersion>
                    articleList= Database.query(qryString);
                maxSize = articleList.size() ;
                // maxSize = maxSize.divide(PAGE_NUMBER,2,System.RoundingMode.UP);
            }
        } catch(Exception e) {
            Apexpages.addmessages( e );
        }
        if(categoryFilter =='') {
            // maxSize = 0;
            categoryCondition = 'Products:All' ;
        }
        return categoryCondition;
    }
    // Action call when the new list needs to be fetched
    public PageReference refreshSearchResult() {
        maxSize = currentPage = 1;
        return null;
    }
    // Returns whether we need to see previous button or not
    public boolean getPrevRequired() {
        return currentPage > 1;
    }
    // Returns whether we need to see next button or not
    public boolean getNextRequired() {
        return currentPage * PAGE_NUMBER < maxSize;
    }
    //Returns current page number
    public Decimal getCurrentPageNumber() {
        return this.currentPage;
    }
    //action for next click
    public PageReference next() {
        if(maxSize > this.currentPage * PAGE_NUMBER) {
            this.currentPage = this.currentPage + 1;
        }
        return null;
    }
    //action for previous click
    public PageReference previous() {
        if(this.currentPage > 1)
            this.currentPage = this.currentPage - 1;
        return null;
    }
}

 
Hi all, I have a big problem, hope someone can help me. I successfully configured Live agent in a salesforce production org. After it, I edited my main chat button by setting a pre-chat page. Here is the screenshot of configuration of my button.User-added image
And this is the code of the visualforce pre-chat page (LiveAgentPreChatPage): this is accessible through force.com Site I created for this scope.

<apex:page showHeader="false">

<!-- This script takes the endpoint URL parameter passed from the deployment page and makes it the action for the form -->
<script type='text/javascript'>
(function() {
function handlePageLoad() {
var endpointMatcher = new RegExp("[\\?\\&]endpoint=([^&#]*)");
document.getElementById('prechatForm').setAttribute('action',
decodeURIComponent(endpointMatcher.exec(document.location.search)[1]));
} if (window.addEventListener) {
window.addEventListener('load', handlePageLoad, false);
} else { window.attachEvent('onload', handlePageLoad, false);
}})();
</script>

<h1>Live Agent Pre-Chat Form</h1>

<!-- Form that gathers information from the chat visitor and sets the values to Live Agent Custom Details used later in the example -->
<form method='post' id='prechatForm'>
    First name: <input type='text' name='liveagent.prechat:ContactFirstName' id='firstName' /><br />
    Last name: <input type='text' name='liveagent.prechat:ContactLastName' id='lastName' /><br />
    Email: <input type='text' name='liveagent.prechat:ContactEmail' id='email' /><br />
    Phone: <input type='text' name='liveagent.prechat:ContactPhone' id='phone' /><br />
    Issue: <input type='text' name='liveagent.prechat:CaseSubject' id='subject' /><br />

<!-- Hidden fields used to set additional custom details -->
    <input type="hidden" name="liveagent.prechat:CaseStatus" value="New" /><br />
    
    <!-- This example assumes that "Chat" was added as picklist value to the Case Origin field -->
    <input type="hidden" name="liveagent.prechat:CaseOrigin" value="Chat" /><br />
    
    <!-- This example will set the Case Record Type to a specific value for the record type configured on the org. Lookup the case record type's id on your org and set it here -->
    <input type="hidden" name="liveagent.prechat:CaseRecordType" value="012D0000000Eyni" />
    
    <!-- Used to set the visitor's name for the agent in the Console -->
    <input type="hidden" name="liveagent.prechat.name" id="prechat_field_name" />

<!-- map: Use the data from prechat form to map it to the Salesforce record's fields -->
<input type="hidden" name="liveagent.prechat.findorcreate.map:Contact" value="FirstName,ContactFirstName;LastName,ContactLastName;Email,ContactEmail;Phone,ContactPhone" />

<input type="hidden" name="liveagent.prechat.findorcreate.map:Case" value="Subject,CaseSubject;Status,CaseStatus;Origin,CaseOrigin" />

<!-- doFind, doCreate and isExactMatch example for a Contact: 
    Find a contact whose Email exactly matches the value provided by the customer in the form 
    If there's no match, then create a Contact record and set it's First Name, Last Name, Email, and Phone to the values provided by the customer -->
<input type="hidden" name="liveagent.prechat.findorcreate.map.doFind:Contact" value="Email,true" />
<input type="hidden" name="liveagent.prechat.findorcreate.map.isExactMatch:Contact" value="Email,true" />
<input type="hidden" name="liveagent.prechat.findorcreate.map.doCreate:Contact" value="FirstName,true;LastName,true;Email,true;Phone,true" />

<!-- doCreate example for a Case: create a case to attach to the chat, set the Case Subject to the value provided by the customer and set the case's Status and Origin fields -->
<input type="hidden" name="liveagent.prechat.findorcreate.map.doCreate:Case" value="Subject,true;Status,true;Origin,true" />

<!-- linkToEntity: Set the record Contact record, found/created above, as the Contact on the Case that's created --> 
<input type="hidden" name="liveagent.prechat.findorcreate.linkToEntity:Contact" value="Case,ContactId" />

<!-- showOnCreate: Open the Contact and Case records as sub-tabs to the chat for the agent in the Console -->
<input type="hidden" name="liveagent.prechat.findorcreate.showOnCreate:Contact" value="true" />
<input type="hidden" name="liveagent.prechat.findorcreate.showOnCreate:Case" value="true" />

<!-- saveToTranscript: Associates the records found / created, i.e. Contact and Case, to the Live Chat Transcript record. --> 
<input type="hidden" name="liveagent.prechat.findorcreate.saveToTranscript:Contact" value="ContactId" />
<input type="hidden" name="liveagent.prechat.findorcreate.saveToTranscript:Case" value="CaseId" />

<!-- displayToAgent: Hides the case record type from the agent -->
<input type="hidden" name="liveagent.prechat.findorcreate.displayToAgent:CaseRecordType" value="false" />

<!-- searchKnowledge: Searches knowledge article based on the text, this assumes that Knowledge is setup -->
<input type="hidden" name="liveagent.prechat.knowledgeSearch:CaseSubject" value="true" />

<input type='submit' value='Chat Now' id='prechat_submit' onclick="setName()"/>

<!-- Set the visitor's name for the agent in the Console to first and last name provided by the customer -->
<script type="text/javascript">
   function setName() {
    document.getElementById("prechat_field_name").value =  
        document.getElementById("firstName").value + " " + document.getElementById("lastName").value;
    }
</script>

<style type="text/css">
p {font-weight: bolder }
</style>

</form>
</apex:page>


I can view my pre-chat page and I can also chat between the agent and the visitor, but Sf does not create contact record neither the Case one. Debug logs don't tell me anything. Javascript console does not give me any error message too. Can anyone please help me? Or tell me how I can debug live agent code in order to understand where I'm making mistake?
If you need from me some other detail that can explain better problem, don't hesitate to tell me.
Thank you in advance.
Maria
Hi all,
I'm implementing KnowledgeArticles  - and I keep running in to issues with this architecture...

I cna't seem to get knowledge article versions sorted by the CaseAssosciationCount...

Here is the query I am  trying to run:
SELECT id FROM KnowledgeArticleVersion WHERE Language = 'en_US' AND PublishStatus = 'Online' AND ValidationStatus = 'Validated' ORDER BY KnowledgeArticle.CaseAssociationCount DESC


And I get my lovely error:
ERROR at Row:1:Column:138
Didn't understand relationship 'KnowledgeArticle' in field path. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names.

What the hell SF? You're tellin me I can't query parent values? how am I supposed to enforce my where clause ?!
  • August 05, 2015
  • Like
  • 0
I added Knowledge Articles to our Site.com site using a Data repeater. When Guest Users and Customer Community Users view our Site.com website, they can't see the articles and get the following error: "We're unable to retrieve your data due to an error".

Guest Users and Customer Community Users are able to access Custom Objects.

Relevant Community User and Guest User Profile Settings:
Tab Settings - Knowledge - Default On
General User Permissions - Knowledge One - Checked
Article Type Permissions - Site Content Articles - Basic Access - Read - Checked

How can I enable Guest Users and Customer Community User to view Knowledge Articles in Site.com?