Lightning Component for Wikipedia search

Author posted by Jitendra on Posted on under category Categories Salesforce and tagged as Tags with 3 Comments on Lightning Component for Wikipedia search

Initially I thought creating Wikipedia Search component will be straight forward. I can simply use AJAX request from Lightning component to get result from Wikipedia using its REST API. Soon, I discovered about Content Security Policy in Lightning components developer guide.

If we attempt to use AJAX or REST API in Lightning component then below error will be thrown

Uncaught error in markup://ui:keyup : caught Failed to execute ‘open’ on ‘XMLHttpRequest’: Refused to connect to ‘https://en.wikipedia.org/w/api.php?action=opensearch&search=jitendra&limit=10&namespace=0&format=jsonfm’ because it violates the document’s Content Security Policy.

So, other workaround I came up is by using Apex controller to create HttpRequest and return result as JSON to lightning component. You can download this as unmanage package from this URL.

Salesforce Lightning Component for Wikipedia Search
Salesforce Lightning Component for Wikipedia Search

WikiHttpRequest.class

/**
 * Author	:	Jitendra Zaa
 * Desc		:	This Controller is used by Lightning component to make Http request to Wikipedia
 * */
public class WikiHttpRequest {

    @AuraEnabled
    public static String getWikiResponse(String searchText, Integer searchLimit){
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://en.wikipedia.org/w/api.php?action=opensearch&search='+searchText+'&limit='+
                        searchLimit+'&namespace=0&format=json');
		req.setMethod('GET');
        
        Http http = new Http();
		HTTPResponse res = http.send(req);  
		return res.getBody();
    }
}

Above class defines method “getWikiResponse” which is annotated by @AuraEnable so that it can be accessed from Lightning component. This method takes two arguments, one text to be searched on Wikipedia and total number of results to be returned. Don’t forget to add “https://en.wikipedia.org” in remote site settings so that Salesforce can connect to external URL.

Test Class to fake Http response using HttpCalloutMock class.

/**
 * Author	:	Jitendra Zaa
 * Desc		:	Test class for Lightning controller WikiHttpRequest
 * */
@isTest
public class MockWikiHttpRequest implements HttpCalloutMock {
    // Implement this interface method
    public HTTPResponse respond(HTTPRequest req) { 
        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        res.setBody('["jitendra", ["Jitendra"], ["Jitendra may refer to:"] , ["https://en.wikipedia.org/wiki/Jitendra"] ]');
        res.setStatusCode(200);
        return res;
    }
    
    @isTest
    static void getWikiResponse_Test(){
        
        Test.setMock(HttpCalloutMock.class, new MockWikiHttpRequest());
       
        String response = WikiHttpRequest.getWikiResponse('Jitendra',1);
        
		System.assertEquals(response, 
                            '["jitendra", ["Jitendra"], ["Jitendra may refer to:"] , ["https://en.wikipedia.org/wiki/Jitendra"] ]') ;
        
    }
}

We would be using “Salesforce Lightning Design System (SLDS)” to give our component same look and full as of standard Salesforce lightning component. Download SLDS and save it as a static resource by name “SLDS090”. We will not be using any library and everything would be pure JavaScript based.

WikiSearch.cmp

 <aura:component controller="WikiHttpRequest" implements="force:appHostable,flexipage:availableForAllPageTypes">
	<ltng:require styles="/resource/SLDS090/assets/styles/salesforce-lightning-design-system.css"/>
    <aura:attribute name="txtWikiText" type="String"/>
    <aura:attribute name="resultLimit" type="Integer" default="4"/> 

<div class="slds-card">

<div class="slds-card__header slds-grid">

<div class="slds-media slds-media--center slds-has-flexi-truncate">

<div class="slds-media__figure">
          <c:svg class="slds-icon slds-icon--small slds-icon-standard-account" xlinkHref="/resource/SLDS090/assets/icons/custom-sprite/svg/symbols.svg#custom68" /> 
      </div>


<div class="slds-media__body">

<h2 class="slds-text-heading--small slds-truncate">Wikipedia Search</h2>

      </div>

  
    </div>

 
  </div>


<div class="slds-card__body slds-box slds-theme--default">

<div class="slds-grid slds-wrap">

<div class="slds-col slds-size--10-of-12">
          	<ui:inputText value="{!v.txtWikiText}" placeholder="Hit enter button to search" class="slds-input" keyup="{!c.searchWiki}"/>    
          </div>


<div class="slds-col slds-size--2-of-12">
          <button class="slds-m-left--small slds-button slds-button--icon-border-filled slds-button--icon-small" onclick="{!c.searchWikiOnButton}">
                <c:svg class="slds-button__icon" xlinkHref="/resource/SLDS090/assets/icons/utility-sprite/svg/symbols.svg#search" />
              <span class="slds-assistive-text">Settings</span>
            </button>
          </div>


<div class="slds-col slds-size--10-of-12 slds-p-top--large">

<ul id="resultPlaceHolder" class="slds-list--vertical slds-has-cards slds-has-inline-block-links--space">
                  <!-- This is placeholder to render Wiki Search results -->
              </ul>

 
          </div>


<div class="slds-col slds-size--2-of-12"></div>

 
        </div>

 
      </div>

 
   </div>

 
</aura:component>

Above component implements “force:appHostable” to inform Lightning platform that it can be added as a navigation menu in Salesforce1 mobile application.

Interface flexipage:availableForAllPageTypes means that this component can be added on any record home pagelayout using drag and drop interface of “Lightning App Builder”.

We are also using “svg” component to display icon in our component. Source code of this component is borrowed from this trailhead module.

WikiSearchController.js

({
	searchWiki : function(component, event, helper) { 
        if(event.getParams().keyCode == 13){   
            helper.wikiCallOut(component.get('v.txtWikiText'),component, helper); 
        }
	},
    searchWikiOnButton : function(component, event, helper){ 
        helper.wikiCallOut(component.get('v.txtWikiText'),component, helper); 
    }
})

WikiSearchHelper.js

({
	wikiCallOut : function(txtToSearch , component, helper) {
        
        var action = component.get('c.getWikiResponse');
        var resLimit = component.get('v.resultLimit');
        action.setParams({
            searchText : txtToSearch,
            searchLimit : resLimit
        });
        
        action.setCallback(this, function(a) {
            if (a.getState() === 'SUCCESS') {
                helper.parseResult(a.getReturnValue(),helper);                
            }  
        });
        $A.enqueueAction(action);   
	},
    parseResult : function(res,helper){
        var retJSON = JSON.parse(res);
        var jsonTitles = retJSON[1] ; 
        var jsonDetails = retJSON[2];
        var jsonURL = retJSON[3];
        
        domSearch = document.getElementById('resultPlaceHolder');
        while (domSearch.firstChild) {
            domSearch.removeChild(domSearch.firstChild);
        }
        
        for(var i=0 ; i&lt;jsonTitles.length ; i++)
        {
           helper.createChildNodes(domSearch, jsonTitles[i],jsonDetails[i],jsonURL[i]); 
        }
        
    },
    
    createChildNodes : function(domSearch,title,desc,url){ 
        var res_li = document.createElement('li');
        res_li.setAttribute('class', 'slds-list__item'); 
                
        var desc_span = document.createElement('span');
        desc_span.innerText = ' '+desc ;
        desc_span.setAttribute('class', 'slds-text-body--small');  
        
        
        var link = document.createElement('a');
        link.setAttribute('href', url);
        link.innerText = title ;
        
        res_li.appendChild(link);
        res_li.appendChild(desc_span);
        domSearch.appendChild(res_li); 
    }
})

Passing parameter to Lightning Component from “Lightning App Builder

We can configure this component to decide how many results can be returned from Lightning App builder interface. As shown in below video, when we drag and drop component on any record’s page-layout , its parameter can also be specified at same time.

To set Lightning component parameter from “App Builder” we need to use “Design” bundle of lightning component.

WikiSearch.design

<design:component>
	<design:attribute name="resultLimit" label="Result Limit" description="Total number of results to display" />
</design:component>

Related posts

  • Nisha

    this is not searching anything.Can you tell me what could be happen?

    • what error you are getting in browser console ? is wikipedia added in remote site settings ?

  • GUHA ANANDH

    Hi Jitendra… I couldn’t find this component in the custom component section in the lightning edit page in Account record.
    Is there any settings am missing?