Monday, October 23, 2017

Briefing on NPM - nodejs

Node js is a Javascript runtime which allows us to execute Javscript without browser, thus allows us to use Javascript at server level / as a command prompt application.

Node JS also has NPM, short form of Node Package Ecosystem, which allows users to share Javascript libraries / frameworks to other developers and is being widely used across globe. NPM makes it simple to add / install any javascript framwork into the project and also helps in keeping the frameworks updated.

In this article we go through npm on a high level.

First, to install Node JS in your machine, open NodeJS.org and download the executable as per your Machine specs.


Once Node JS installed in the machine, it adds Node.js Command Prompt through which we execute the npm and node commands.

Using NPM

Upon installing Node Js, a new folder 'node_modules' in current user's user folder.
Eg: C:\Users\laxmi\node_modules 

As stated above, through npm, we can add / install any packages on the fly, without the need of going to the particular site and downloading the packages. We can install the files globally i.e. in node_modules folder or also locally, i.e. in a  project folder.

Let us run a sample install npm for jquery. Command as below
npm install <<Package name>>
This installs latest JQuery framework to the global folder "node_modules", here 3.2.1
We can now use these files in any of our projects. In order to install it locally, navigate the Node Command prompt to the corresponding folder and execute the same command.

In order to manage the NPM packages in better way, we have 'package.json'. This has some basic configuration attributes to provide info about Project, like project name, version, dependencies of the project, i.e. list of the frameworks being used.

in order to create basic package.json file, execute below command
npm init 
This command promts for details in it, about name, version, license. To avoid all these, add 'yes' or 'y' option to it.
npm init -yes
Sample package.json file is as below
{
  "version": "1.0.0",
  "name": "demo",
  "dependencies": {
    "jquery": "^3.2.1",
    "bootstrap": "3.1"
  }
}
Now if we run the npm install command, it installs all the dependencies into the project.

To learn more about npm, use below references.

https://docs.npmjs.com/

http://nodesource.com/blog/the-basics-of-package-json-in-node-js-and-npm/ 

Friday, May 19, 2017

Instantiation of a Page Reference in Apex, Salesforce

In many cases, after a custom action performed, we may need to redirect the page to a different page, could be another Visualforce page / standard Page like a list view of an object or any of default pages like view / edit page of a record or a new record entry page.

Page redirection happens in Apex code using PageReference class.

There are multiple ways to instantiate a page reference in Apex. Below are list of all possible ways.

Approach 1:
PageReference pageRef = new PageReference('***partialURL***');
PageReference pageRef = new PageReference('***FullURL***');

Eg:

PageReference pageRef = new PageReference('/apex/CustomPage1?id=xxxxxx');
PageReference pageRef = new PageReference('/a04');

PageReference pageRef = new PageReference('http://www.google.com');

Approach 2:
PageReference pageRef = Page.<<VF Page Name>>;

Eg:

PageReference pageRef = Page.CustomPage;
pageRef.getParameters().put('id','XXXXXXX');

Approach 3:
Refer stnadard pages of an Object / record

PageReference pageRef = new ApexPages.StandardController(recordObj).edit();
PageReference pageRef = new ApexPages.StandardController(recordObj).view();

Refer List view of an object

PageReference pageRef = new PageReference('/'+<<Object>>.sObjectType.getDescribe().getKeyPrefix());

PS: Try not to hard code URLs and use above available options to build the URLs.

Friday, April 21, 2017

Display Validation rule Errors on a Visualforce Page

One among the most useful features in Salesforce is Validation rules in an object. With Validation rules, e can provide a formula / conditional check and if it met, we display an error message to end user and thus stopping user from saving the record.  The advantage of validation rules is that it validates records when entered in forms and also through other means like data loader. So, if there are any conditions which are mandatory, better to have them in Validation rules, even though you have custom forms.

A simple example in my application is, we can't allow users to provide weight less than 1 LBS. To accomplish this, we added a validation rule as below.

And, in our application, we are having Visualforce pages for the forms as we have some complex functionalities which can't be accomplished through default layouts.

In order to display errors on forms like mandatory field / invalid value , we simply need to provide a visualforce component / tag "<apex:pagemessages />" in the layout as per our design. By adding this, upon save of an object, if there are any errors in data, they are listed in pagemessages section.

But, Validation rules, don't come under default errors of a data record. They actually through DML Exceptions. So, in order to show the validation errors, in the Apex class save method, we need to catch the  DML exceptions and just provide the exception to Apexpage messages. It parses the error messages and displays them in page messages. Below is sample code.

public class customController
{
    public object__C obj {get;set;}
    
    public customController(ApexPages.StandardController ctlr)
    {
        //Consturctor, define obj here.
    }
    
    public pagereference custommSave()
    {
        try
        {
            upsert obj;
            return new pagereference('/'+obj.id);
        }         
        catch(DmlException ex){
            ApexPages.addMessages(ex);
            return null;
        }
        catch(Exception ex){
            //Handle exception
            return null;
        }
    }
}

Happy coding!

Monday, February 13, 2017

Enable / Setup Search Service in Sharepoint through Powershell

Sharepoint has provided an easy approach through Central admin to enable Search service application, but the one known issue with it is, it creates a database on its own. we can also enable this using powershell commands. By doing this, we can provide our own name for the DB.

Below is the step by step commands to be executed to enable Search service using powershell.
 #Add-PSSnapin Microsoft.SharePoint.PowerShell  
 # 1.Setting up some initial variables.  
 write-host 1.Setting up some initial variables.  
 $SSAName = "InternalSearch"  
 $SSADatabase = "InternalSearchDB"  
 $saAppPoolName = "SecurityTokenServiceApplicationPool"  
 $SSI = get-spenterprisesearchserviceinstance -local  
 $err = $null  
 # Start Services search services for SSI  
 write-host Start Services search services for SSI  
 Start-SPEnterpriseSearchServiceInstance -Identity $SSI  
 Start-SPEnterpriseSearchQueryAndSiteSettingsServiceInstance $SSI  
 # 2.connect to an Application Pool.  
 write-host 2.connect to an Application Pool.  
 $AppPool = Get-SPServiceApplicationPool $saAppPoolName  
 # 3.Create the SearchApplication and set it to a variable  
 write-host 3.Create the SearchApplication and set it to a variable  
 $SearchApp = New-SPEnterpriseSearchServiceApplication -Name $SSAName -applicationpool $AppPool -databasename $SSADatabase  
 #4 Create search service application proxy  
 write-host 4 Create search service application proxy  
 $SSAProxy = new-spenterprisesearchserviceapplicationproxy -name $SSAName" ApplicationProxy" -Uri $SearchApp.Uri.AbsoluteURI  
 # 5.Provision Search Admin Component.  
 write-host 5.Provision Search Admin Component.  
 set-SPenterprisesearchadministrationcomponent -searchapplication $SearchApp -searchserviceinstance $SSI  
 # 6.Create a new Crawl Topology.  
 write-host 6.Create a new Crawl Topology.  
 $CrawlTopo = $SearchApp | New-SPEnterpriseSearchCrawlTopology  
 # 7.Create a new Crawl Store.  
 write-host 7.Create a new Crawl Store.  
 $CrawlStore = $SearchApp | Get-SPEnterpriseSearchCrawlDatabase  
 # 8.Create a new Crawl Component.  
 write-host 8.Create a new Crawl Component.  
 New-SPEnterpriseSearchCrawlComponent -CrawlTopology $CrawlTopo -CrawlDatabase $CrawlStore -SearchServiceInstance $SSI  
 # 9.Activate the Crawl Topology.  
 write-host 9.Activate the Crawl Topology.  
 do  
 {  
   $err = $null  
   $CrawlTopo | Set-SPEnterpriseSearchCrawlTopology -Active -ErrorVariable err  
   if ($CrawlTopo.State -eq "Active")  
   {  
     $err = $null  
   }  
   Start-Sleep -Seconds 10  
 }  
 until ($err -eq $null)  
 # 10.Create a new Query Topology.  
 write-host 10.Create a new Query Topology.  
 $QueryTopo = $SearchApp | New-SPenterpriseSEarchQueryTopology -partitions 1  
 # 11.Create a variable for the Query Partition  
 write-host 11.Create a variable for the Query Partition  
 $Partition1 = ($QueryTopo | Get-SPEnterpriseSearchIndexPartition)  
 # 12.Create a Query Component.  
 write-host 12.Create a Query Component.  
 New-SPEnterpriseSearchQueryComponent -indexpartition $Partition1 -QueryTopology $QueryTopo -SearchServiceInstance $SSI  
 # 13.Create a variable for the Property Store DB.  
 write-host 13.Create a variable for the Property Store DB.  
 $PropDB = $SearchApp | Get-SPEnterpriseSearchPropertyDatabase  
 # 14.Set the Query Partition to use the Property Store DB.  
 write-host 14.Set the Query Partition to use the Property Store DB.  
 $Partition1 | Set-SPEnterpriseSearchIndexPartition -PropertyDatabase $PropDB  
 # 15.Activate the Query Topology.  
 write-host 15.Activate the Query Topology.  
 do  
 {  
   $err = $null  
   $QueryTopo | Set-SPEnterpriseSearchQueryTopology -Active -ErrorVariable err -ErrorAction SilentlyContinue  
   Start-Sleep -Seconds 10  
   if ($QueryTopo.State -eq "Active")  
     {  
       $err = $null  
     }  
 }  
 until ($err -eq $null)  
 Write-host "Your search application $SSAName is now ready"  

Sunday, February 12, 2017

Migrate Sharepoint User Account to a New Login Name

There might be many occasions where we have to change the Users' account, could be the domain change or name change.

 Also another scenario is, if we have enabled Farm based authentication sharepoint adds some special characters to the account in the start like 'i:0#.w|' and if  we disabled it at later point, these names will not be changed.  We need to migrate / change the account names manually before people start using it. If not, we see 2 accounts for individual users.

we can achieve this functionality using Poweshell script. Considering above scenario, below is the script used to migrate resources in bulk when we are moving back form Farm based to windows authentication.

Below script is to get all the people present in the current system to a CSV File.
 function GetSPWebUsers($SiteCollectionURL)   
 {   
   [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null   
   $site = new-object Microsoft.SharePoint.SPSite($SiteCollectionURL)   
   $web = $site.openweb()   
   $siteUsers = $web.SiteUsers   
 @(foreach ($user in $siteUsers) {  
   $usergroup = New-Object System.Object  
      $usergroup | Add-Member -type NoteProperty -name AccountName -value $user.LoginName  
    Write-Output $usergroup   
 }) | Export-Csv c:\userlist.csv -NoTypeInformation   
   $web.Dispose()   
   $site.Dispose()   
 }   
 GetSPWebUsers $args[0]  
 #to execute, run the command as below  
 #GetSPWebUsers "http://<<site collection URL>>"  

By running above script, we get all the users' login names to a CSV file which will be used as an input of below code where we migrate individual users to the windows accounts which are formed by removing the starting set of special characters "i:0#.w|"
 Add-PSSnapin Microsoft.SharePoint.PowerShell  
 function MigrateUserOrGroups($csvFile)  
 {  
   #Getting the SPFarm object  
   $farm = Get-SPFarm  
   Import-Csv $csvFile | ForEach-Object{  
   Write-Host "Migrating User" $_.login "to" $_.login.Substring(7) -ForegroundColor Green  
   $farm.MigrateUserAccount( $_.login, $_.login.Substring(7), $false )  
   Write-Host "Migration Completed" -ForegroundColor Cyan  
   }  
   # $farm.Name  
 }  
 MigrateUserOrGroups $args[0]  
 #to execute, run the command as below  
 #MigrateUserOrGroups "c:\userlist.csv"  

You can modify the code as per your requirement.

Thursday, February 9, 2017

Display Files / Folders from a Document Library in Sharepoint

Below is the code to display documents / folders from a library in a Sharepoint environment, in a Tree View.

we are using SPServices and JQuery to achieve this  functionality.

 <div id='status' style='color:#d41414;display:none;padding:5px'>  
 </div>  
 <div id='main-block' style='display:none'>  
      <div><h3>Documents</h3></div>  
      <div id="0">  
      </div>  
 </div>  
 <script src="/InternalResources/jquery.min.js"></script>  
 <script src="/InternalResources/jquery.SPServices-0.7.2.min.js"></script>  
 <script language="javascript" type="text/javascript">  
 $(document).ready(function(){  
      //Enter the list name. If url is different, please update url variable too.  
      //Here code takes the current context and current website  
   var list = "TestFolders";  
   var url = list + "/";   
      createTree(url, 0, list);       
  });  
 function createTree(url, tagID, list){  
   //get the url to define the level of tree,  
   $().SPServices({  
   operation: "GetListItems",  
   async: false,  
   listName: list,  
   CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='ID' /><FieldRef Name='EncodedAbsUrl' /></ViewFields>",  
   CAMLQueryOptions: "<QueryOptions><Folder>" + url + "</Folder></QueryOptions>",  
   completefunc: function (xData, Status) {  
           if($(xData.responseXML).SPFilterNode("z:row").length > 0) {  
                $("#"+tagID+"").append("<ul id='prime-"+tagID+"'>");  
                $(xData.responseXML).SPFilterNode("z:row").each(function() {  
                     var id = $(this).attr("ows_ID");  
                     var title = $(this).attr("ows_Title");     
                     var folder =  $(this).attr("ows_FileLeafRef").split(";#")[1];   
                     $("#prime-"+tagID+"").append("<li id='"+id+"'>" + " <a href='"+$(this).attr("ows_EncodedAbsUrl")+"'>" + folder + " </a></li>");                  
                 var thisFSObjType = $(this).attr("ows_FSObjType").split(";#")[1];  
                 if(thisFSObjType == 1) {  
                     //auto call the function createTree again, to get subfolders and files, assigning a new url/subfolder and id  
                     createTree(url+'/'+folder, id, list);       
                 }  
                 });  
                 $("#"+tagID+"").append("</ul>");  
                 $('#status').css('display','none');  
                 $('#main-block').css('display','block');  
           }  
           else     {  
                $('#status').html('No documents found.');  
                $('#status').css('display','block');  
           }  
      }  
  });   
 }  
 </script>  

Takeaways from Threshold limits of Sharepoint Lists

Few takeaways of Sharepoint Lists with large size.

  • If the data crossed the threshold value, applying filters on multiple indexed columns won’t display records. 
  • The first filter should be the Indexed column and only one indexed column should be used in a filter criteria
  • We cant index a column which has multi select enabled.
  • Threshold will not effect the performance of an individual item access.
  • If list crosses view threshold, we can't use it as lookup reference in any other list. 
Also, its better not to apply many permission restrictions  as it checks for individual permission set while fetching a record, which may impact performance.

For reference, use below links.

https://support.office.com/en-us/article/Manage-large-lists-and-libraries-in-SharePoint-b8588dae-9387-48c2-9248-c24122f07c59

https://support.office.com/en-us/article/Manage-lists-and-libraries-with-many-items-fba0c8b7-79bb-4ea4-9aff-bf145a689e8e



 

Monday, January 30, 2017

Run Sharepoint Designer 2013 using Different Account

We no more have an option to switch the user account in Sharepoint Designer 2013. In earlier version (2010), we have a direct option in designer, where we have a user icon to bottom left of the screen. Upon clicking it, it pops up a window to change user account.
In 2013, we can run / start the designer with a different account by providing the other user credentials. The steps to follow, is as below.
  • Open Sharepoint designer Installation folder, in general it would be in below location
    C:\Program Files(x86)\Microsoft Office\Office15
  • Select the file named 'SPDESIGN.EXE', hold the Shift key and Right click on it
  • In the Context menu, click on 'Run as different user'. This opens up a Windows security window
  • Provide the credentials of the user with which you need to run it.
Now, the designer will be opened with provided User.

Or, the other option is to login to the system it self with the other account.

Reference: https://support.microsoft.com/en-in/help/2738178/you-cannot-switch-the-user-account-in-sharepoint-designer-2013

Tuesday, January 24, 2017

Picklists are more flexible now, in Salesforce

It was a difficult task for developers / admins to change a value in a Picklist in salesforce, as the values are directly stored in the records and if any formula fields are derived on picklist values, has to be changed. Similarly in the APEX / Visualforce code, if there is any logic based on picklist values, has to be changed.

Salesforce eased this burden in Spring 17 release.  Now on wards we have 2 values for a Picklist value, one is a label and other one is API name.
Basically the values stored in the back end in a record are API Names. When we try to get the value of a field, it fetches API value. From above picture, if we try to pull value for obj.Urgency__c, the result will be Urgent.

So, all our formulae fields' logic and also in the apex code, we can go with API names. And, we can change the label value at any point of time as per customer's need.

In order to display Picklist value in a visualforce page, make sure we go with OutputField only, to get picklist value label.  If we directly go by object field, it would display API name.

<apex:outputField value="{!obj.Urgency__c}"/>

 Few Points to consider for Picklist API Names:
  • For the first time when we create Picklist values, provided values will go into label and API Name
  • At any point, we are allowed to change API names too, by editing individual value.
  • We can also restrict API name updates through a setting. This blocks users from updating API names of all Picklist values in the Org.
  • To enable / disable above setting, go to Settings->Administer->Data Management->Picklist settings.
Reference, https://developer.salesforce.com/blogs/developer-relations/2017/01/keeping-picklist-integrations-safe-using-api-names.html

Sunday, January 22, 2017

Update List Items without modifing System columns in Sharepoint

Its most common we need to update few column values in backed without changing system columns like Modified By, Modified On in a Sharepoint list / document library.

In order to achieve this, we need to go with Item.SystemUpdate() instead of Item.Update() in your C# code.

In case, if its a one time activity and we need to update data in bulk, the easiest way is to go with PowerShell script. Below is the example to update a column value in a list without changing Modified On and Modified By values, using PowerShell.

 Add-PSSnapin microsoft.sharepoint.powershell  
 $web = Get-SPWeb "<<Site URL>>"  
 $list = $web.lists["<<List Name>>"]  
 #Get all items in particular list and save them to a variable.   
 #Here you can also apply your CAML query to fetch particular set of records  
 $items = $list.items  
 #Go through all list items  
 foreach($item in $items)  
 {       
      #If any conditions are required, can set them here in if clause.  
      #Update the fields as below.  
      $item["<<Field Display Name>>"] = "<<Value>>";  
      #This is the important change, using systemupdate will just set the above fields.  
      #This will not update Modified & Modified By Fields.  
      $item.SystemUpdate();  
 }  
 $web.Dispose();