• Brooks Johnson 6
  • NEWBIE
  • 95 Points
  • Member since 2017

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 34
    Questions
  • 42
    Replies

Hi Friends, 

I have a requirement for users to be able to download data to a CSV from a button click.  I had implemented a solution in the Aura controller that worked as long as the number of records was under a few thousand but fails with larger volume and the client wants to export up to around 7k records.  Note that the current solution works in Safari but fails in Chrome and Firefox. 

Below is the current solution. 

The controller

handleExport: function(component, event, helper){

        var contactList = component.get('v.completeResults');
        var csv = helper.convertListToCSV(component, contactList);

        var hiddenElement = document.createElement('a');
        hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
        hiddenElement.target = '_self'; //
        hiddenElement.download = 'EmailSendList.csv';  // CSV file Name* you can change it.[only name not .csv]
        document.body.appendChild(hiddenElement); // Required for FireFox browser
        hiddenElement.click(); // using click() js function to download csv file

    }


This is the helper
convertListToCSV: function (component, list) {

        var csvStringResult, counter, keys, columnDivider, lineDivider;
        var csvHeader = '*** Changes to CSV Will Not be Saved Back To Event App *** ';

        // check if "list" parameter is null, then return from function
        if (list == null || !list.length) {
            return null;
        }
        // store ,[comma] in columnDivider variabel for sparate CSV values and
        // for start next line use '\n' [new line] in lineDivider varaible
        columnDivider = ',';
        lineDivider =  '\n';

        // in the keys valirable store fields API Names as a key
        // this labels use in CSV file header
        keys = ['Delivery_Name', 'InformalSalutation', 'Last_Name', 'Email1', 'Inviter_Name', 'GalileoId', 'Relationship_Type',
                'Age', 'BAOffice', 'MarketingRestrictions', 'OptOut', 'PrimaryContact', 'BillingCity', 'BillingState',
                'Company', 'BA_Relationship', 'LastModifiedName', 'LastModifiedDate', 'LastModifiedDate', 'contactId'];

        csvStringResult = csvHeader + lineDivider;
        csvStringResult += keys.join(columnDivider);
        csvStringResult += lineDivider;

        for(var i=0; i < list.length; i++){
            counter = 0;

            for(var sTempkey in keys) {
                var skey = keys[sTempkey] ;

                // add , [comma] after every String value,. [except first]
                if(counter > 0){
                    csvStringResult += columnDivider;
                }
                csvStringResult += '"'+ list[i][skey]+'"';

                counter++;

            } // inner for loop close
            csvStringResult += lineDivider;
        }// outer main for loop close

        // return the CSV format String
        return csvStringResult;
    }
 

I think this needs to be redesigned.  Would I be better off calling a Visualforce page that renders in a csv or should I  generate the CVS string in Apex and pass that to the Aura controller instead of doing it all on the client-side? Or are there better solutions I am not even thinking of?


Hi Friends, 

I am trying to implement some client-side search in a Lightning Component.  It is working when a search term is found. But when I clear out the seach input box the data does not revert to its original state. 

It looks like my original data attribute is overwritten when I  call component.set() with the search results. I have tried making a close of the original data aray with slice(). But that has not worked either. 
Could I get anyone to take a look at the code and tell what I need to do to change state when the search results array is empy.
Here is the component code. 
<div>
              <lightning:input class="searchBar" name="search-send-list" label="Search                         
                  Email Send List" type="search"
                    placeholder="Seach Send List" onchange="{!c.handleSearch}"/                 </div>


Here is the controller 
 
handleSearch : function (component, event, helper) {

        const currentSendList = component.get("v.data");
        let searchTerm = [];
        let searchResults = [];
        searchTerm = event.getSource().get("v.value").toLowerCase();

        if (searchTerm.length > 3){
            for (let i = 0; i < currentSendList.length; i++){
                console.log(currentSendList[i].Last_Name.toLowerCase().indexOf(searchTerm) != -1)
                if(currentSendList[i].Last_Name.toLowerCase().indexOf(searchTerm) != -1){
                    searchResults.push(currentSendList[i]);
                }
            }
        }
        console.log(searchResults.length);
        if (searchResults.length > 0){
            component.set("v.data", searchResults)
        }else {

        }
        console.log(currentSendList);
        console.log(searchTerm);
        console.log('current search results = ' + searchResults);
    }

 

Hi Friends, 

I am stuck on what seems like a pretty trivial problem. I have an LWC meant to display on a Lightning App Page. So I can't get the field values by importing (get record)

This component fetches the value of a single record and then I want to display field values in the HTML. But when I load the page. I get an error that the field is undefined. 

If anyone would be kind enough to take a look I would be grateful. ​​​​​

HTML

<template>
    <lightning-card title="Overall Benchmark Values">

        <p>Program Delivery Rate <span>{benchmarks.Program_Mean_Delivery_Rate__c}%</span></p>
    </lightning-card>
</template>
JS
import {LightningElement, wire, track} from 'lwc';
import getBenchmarkValues from '@salesforce/apex/BenchmarksSelector.getOverAllBenchmarks';

export default class OverAllBenchmarks extends LightningElement {
    @track benchMarks;

    @wire(getBenchmarkValues)wiredBenchmark({data, error}){
        if(data){this.benchMarks = data}
        console.log(data);
        console.log(this.benchMarks);
    }
}
The controller
@AuraEnabled(cacheable=true)
	public static BenchMarks__c getOverAllBenchmarks(){
		BenchMarks__c benchMarks = [SELECT Program_Mean_Delivery_Rate__c FROM BenchMarks__c LIMIT 1];
		return benchMarks;
	}


 

Hi friends, I have three  VF pages that each uses the standard controller. The business case for these is to generate a custom report that exports in PDF.  I have a request for a to be able to generate multiple PDFs at one time. For example, the Region__c button would no longer generate a report for just that region but for every region (18 records)

What would be the best way to implement this? And is it possible using the Standard controller or will we need a custom controller?

The next step to this will be to generate reports on a related child record. All of a regions contacts etc... 

Below is a very truncated version of the page. 

<apex:page id="ProgramPerformanceRegion" showHeader="false" standardController="Region__c" docType="html-5.0"
           sideBar="false" standardStylesheets="false" applyBodyTag="false" applyHtmlTag="false" renderAs="advanced_pdf">
    <head>
        <title>Region Health Check Report</title>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <apex:stylesheet value="{!$Resource.HealthCheckStyle}"/>
    </head>   
    <table width="100%" class="main-text" cellpadding="0" cellspacing="0">
        <tr width="100%" class="main-text">
            <td width="50%" align="left" STYLE="font-size: 20px; font-weight: bold">Program Performance Scorecard</td>
        </tr>
        <tr width ="100%" class="main-text">
            <td width="50%" style="margin: 0">
                <span style="font-size: 18px">
                     <apex:outputText value="{!Region__c.Name}"/>
                </span>
            </td>

        </tr>
    </table>
    <apex:image url="{!$Resource.border_bar}" height="7"/>
    <div style="margin-bottom: 0; padding-bottom: 0">
        <p class="smallFont" style="margin-bottom: 0; padding-bottom: 0">
            The Program Performance Scorecard is a tool by which you can monitor the overall health of your region’s Influencer list.
            The factors that contribute to the overall health grade are listed below. Each category is worth 20% of the grade.
            Your grades are on page 2. This scorecard should be used in conjunction with the internal benchmarks and optimization guidelines to identify areas
            of opportunity and to inform your influencer program strategy.
        </p>
    </div>

    <table width="100%"    class="score_table smallFont" cellspacing="0">
        <tr width="100%"   class="darkBottomBorder smallFont">
            <th colspan="2"    class="darkBottomBorder smallFont" id="scoringConvention"> Scoring Convention </th>
            <th align="center" class="darkBottomBorder a_Color "> A</th>
            <th align="center" class="darkBottomBorder b_Color"> B</th>
            <th align="center" class="darkBottomBorder c_Color"> C</th>
            <th align="center" class="darkBottomBorder d_Color"> D</th>
            <th align="center" class="darkBottomBorder f_Color"> F</th>
        </tr>
        <tr width="15%" class="font smallFont">
            <td rowspan="8" width="15%" align="left" class="smallFont"> Each is worth 20% of overall grade</td>
        </tr>
        <tr class="bottom_border smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border smallFont">List Growth Last<br/> 90 Days</td>
            <td align="center" class="bottom_border smallFont smallFont"> &#8805; 10 </td>
            <td  align="center" class="shaded bottom_border smallFont smallFont">  &#8805; 8</td>
            <td align="center" class="bottom_border smallFont smallFont">  &#8805; 4 </td>
            <td class="shaded bottom_border smallFont smallFont" align="center">  &#8805; 1 </td>
            <td align="center" class="bottom_border smallFont smallFont"> 0 </td>
        </tr>
        <tr class=" smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border"> Percent Contacted</td>
            <td align="center" class="bottom_border smallFont">  &#8805; 50% </td>
            <td  align="center" class="shaded bottom_border smallFont">  &#8805; 35%</td>
            <td align="center" class="bottom_border smallFont">  &#8805; 20% </td>
            <td class="shaded bottom_border smallFont" align="center">  &#8805; 10%</td>
            <td align="center" class="bottom_border smallFont"> &#60; 10% </td>
        </tr>
        <tr class=" smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border">Open Rate</td>
            <td align="center" class="bottom_border smallFont"> &#8805; 35% </td>
            <td  align="center" class="shaded bottom_border smallFont"> &#8805; 25%</td>
            <td align="center" class="bottom_border smallFont"> &#8805; 15% </td>
            <td class="shaded bottom_border smallFont" align="center"> &#8805; 7% </td>
            <td align="center" class="bottom_border smallFont"> &#60; 7% </td>
        </tr>
        <tr class=" smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border">Click Through Rate</td>
            <td align="center" class="bottom_border smallFont"> &#8805; 20% </td>
            <td  align="center" class="shaded bottom_border smallFont"> &#8805; 10%</td>
            <td align="center" class="bottom_border smallFont">  &#8805; 5% </td>
            <td class="shaded bottom_border smallFont" align="center"> &#8805; 2% </td>
            <td align="center" class="bottom_border smallFont"> &#60; 2% </td>
        </tr>
        <tr class=" bottom_border smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border">Unsubscribe Percentage</td>
            <td align="center" class="bottom_border smallFont"> &#60; 2%</td>
            <td  align="center" class="shaded bottom_border smallFont"> &#60; 4%</td>
            <td align="center" class="bottom_border smallFont"> &#60; 6% </td>
            <td class="shaded bottom_border smallFont" align="center"> &#60; 8% </td>
            <td align="center" class="bottom_border smallFont"> &#8805; 8% </td>
        </tr>

    </table>
    <!--    End of rubric section-->
    <!--    Start of Analysis Section-->
    <hr/>
    <span style="font-size: 12px; !important;">
        <apex:outputText escape="false" value=" {!Region__c.Analysis__c}"/>
    </span>

    <!--Start of Footer-->
    <div class="footer smallFont">

    </div>
    <div style="page-break-after: always"></div>
    <apex:image id="logo" url="{!$Resource.Comcast_Logo}" height="50px" width="50px"
               styleClass="img"/>
    <table width="100%" class="main-text" cellpadding="0" cellspacing="0" style="border-collapse: collapse">
        <tr width="100%" class="main-text font">
            <td width="50%" align="left" STYLE="font-size: 22px; font-weight: bold">Program Performance Scorecard</td>
            <td width="50%" align="right" STYLE="font-size: 14px">Overall Health Score</td>
        </tr>
        <tr width ="100%" class="main-text font">
            <td width="50%" style="margin: 0">
                <span style="font-size: 18px;">
                     <apex:outputText value="{!Region__c.Name}"/>
                </span>
            </td>
            <td  width="50%" align="right" style="margin-bottom: 0; padding-bottom: 0">
                     <apex:outputText value="{!Region__c.Grade__c}"
                                      style="font-size: 49px; font-weight: bold;
                                      padding-right: 60px;  font-family: Arial Unicode MS;
                                      padding-bottom: 0px; margin-bottom 0px;
                                     color: {!if(Region__c.Grade__c='A', '#00a846',
                                     if(Region__c.Grade__c='B', '#aabb1a',
                                     if(Region__c.Grade__c='C','#f0b428',
                                     if(Region__c.Grade__c='D', '#FF6428', '#B42846'))))}"/>
            </td>
        </tr>
    </table>
</apex:page>
Hi Friends,

Getting some weird errors when I try to run package:version: create

The classes that are being listed in the errors are in another package. The dependency is defined in the JSON and I  updated this package version today. Any thoughts on what would be going wrong here?

Short of just removing all the dependencies and starting over.
 
ContactStatusManager_Test: Variable does not exist: TestDataFactory,AppSwitcher: An unexpected error occurred. Please include this Err
orId if you contact support: 169023167-52320 (442557440),Admin: In field: apexClass - no ApexClass named CampaignMemberStatusFactory found,CampaignMemberStatusTriggerHandler: Depe
ndent class is invalid and needs recompilation:
 Class CampaignMemberStatusFactory : Variable does not exist: RecordTypeSelector,CampaignMemberStatusFactory: Variable does not exist: RecordTypeSelector,ContactStatusManager_Test
: Variable does not exist: TestDataFactory

 
Hi Friends, 

I am trying to work though the Trailhead Project Develop an App with CLI and Source Control.  When I try to pull down my source from the  CLI I get the following error.

ERROR running force:source:retrieve:  A default package path string is required for SourceWorkspaceAdapter.

With the JSON flag the following is returned.

Thank you in advance for any thoughts on solving this. 
 
$ sfdx force:source:retrieve --manifest assets/package.xml --targetusername pdii --wait 10 --json
{
    "status": 1,
    "name": "missing_package_path",
    "message": "A default package path string is required for SourceWorkspaceAdapter.",
    "exitCode": 1,
    "commandName": "SourceRetrieveCommand",
    "stack": "missing_package_path: A default package path string is required for SourceWorkspaceAdapter.\n    at Function.create (C:\\Users\\Admin\\AppData\\Local\\sfdx\\client\\7.15.3-c7d407d236\\node_modules\\salesforce-alm\\node_modules\\@salesforce\\core\\lib\\sfdxError.js:141:16)\n    at new SourceWorkspaceAdapter (C:\\Users\\Admin\\AppData\\Local\\sfdx\\client\\7.15.3-c7d407d236\\node_modules\\salesforce-alm\\dist\\lib\\source\\sourceWorkspaceAdapter.js:75:36)\n    at Function.create (C:\\Users\\Admin\\AppData\\Local\\sfdx\\client\\7.15.3-c7d407d236\\node_modules\\salesforce-alm\\node_modules\\@salesforce\\kit\\lib\\creatable.js:26:26)\n    at SourceRetrieve.retrieve (C:\\Users\\Admin\\AppData\\Local\\sfdx\\client\\7.15.3-c7d407d236\\node_modules\\salesforce-alm\\dist\\lib\\source\\sourceRetrieve.js:45:74)",
    "warnings": []
}

 
Hi Friends,

Far from a LWC expert here. and trying to get a Lightning Data Table that is sortable. I feel like I have followed everything in the documentation but when I click the arrow in the table header nothing happens. 

Here is my JS
import { LightningElement, track, wire, api } from 'lwc';
import getRecords from '@salesforce/apex/NewToLiftController.getRecords';
import { getRecord } from 'lightning/uiRecordApi';
import { NavigationMixin } from 'lightning/navigation';

const columns = [
    { label: 'First Name', fieldName: 'FirstName', type: "Text", sortable: true},
    { label: 'Last Name', fieldName: 'LastName', type: "Text", sortable: true },
    { label: 'Email', fieldName: 'Email', type: 'Email', sortable: true },
    { label: 'Role', fieldName: 'Role__c', type: 'Text', sortable: true },
    { label: 'Startup Leadership', fieldName: 'Startup_Leadership__c', type: 'boolean', sortable: true },
    { label: 'Company', fieldName: 'CompanyOrAccount', type: 'Text', sortable: true },
];

export default class DatatableBasic extends LightningElement {
@api recordId;
@track data = [];
@track columns = columns;
@track tableLoadingState = true;
@track rowOffset = 0;

@ wire(getRecords, {recordId: '$recordId'})
    wiredRecordsMethod({error, data}) {
        if (data) {this.data = data;
            this.error = undefined;
        } else if (error) {
            this.error = error;
            this.data = undefined;
        }
        this.tableLoadingState = false;
    }
    increaseRowOffset(){this.rowOffset += 1;
    }
    // The method onsort event handler
    updateColumnSorting(event) {
        var fieldName = event.detail.fieldName;
        var sortDirection = event.detail.sortDirection;
        // assign the latest attribute with the sorted column fieldName and sorted direction
        this.sortedBy = fieldName;
        this.sortedDirection = sortDirection;
        this.data = this.sortData(fieldName, sortDirection);        
    }
}
And here is the HTML
 
<template>
            <lightning-card title='First Time Campaign Memebers' icon-name="standard:contact">
                <lightning-datatable
                        key-field="id"
                        data={data}
                        show-row-number-column
                        row-number-offset={rowOffset}
                        hide-checkbox-column
                        columns={columns}
                        sorted-by={sortedBy}
                        sorted-direction={sortedDirection}
                        onsort={updateColumnSorting}
                        is-loading={tableLoadingState}>
                </lightning-datatable>
            </lightning-card>
</template>

 
Hi Everyone

I have a request to get the data that is currently in Pardot under reporting and the email interaction tab and add it to Campaigns in Salesforce.

I have gone through all the API documentation and run various REST queries via Postman to try and get the data but I don't seem to be able to find a way to access it.
Has anyone ever worked with this data outside of Pardot before? And if you can you give some advice on how to get to it?
I have a Visual Force Page that renders as a PDF. I need to add some text to the first page.  It should be below the last </table> tag. But it keeps appearing at the top of the table.  I have marked it with comments to show where it is supposed to appear and where it actually shows up on the PDF. Any help with this formatting would be great. 
 
<div style="margin-bottom: 0; padding-bottom: 0">
        <p class="smallFont" style="margin-bottom: 0; padding-bottom: 0">
            The Program Performance Scorecard is a tool by which you can monitor the overall health of your region’s Influencer list.
            The factors that contribute to the overall health grade are listed below. Each category is worth 20% of the grade.
            Your grades are on page 2. This scorecard should be used in conjunction with the internal benchmarks and optimization guidelines to identify areas
            of opportunity and to inform your influencer program strategy.
        </p>
    </div>
/-//////////////////////////////////////////////////////////////////////////////-/
    /--But instead the text always shows up here --/
/-/////////////////////////////////////////////////////////////////////////////-/

    <table width="100%"    class="score_table smallFont" cellspacing="0">
        <tr width="100%"   class="darkBottomBorder smallFont">
            <th colspan="2"    class="darkBottomBorder smallFont" id="scoringConvention"> Scoring Convention </th>
            <th align="center" class="darkBottomBorder a_Color "> A</th>
            <th align="center" class="darkBottomBorder b_Color"> B</th>
            <th align="center" class="darkBottomBorder c_Color"> C</th>
            <th align="center" class="darkBottomBorder d_Color"> D</th>
            <th align="center" class="darkBottomBorder f_Color"> F</th>
        </tr>
        <tr width="15%" class="font smallFont">
            <td rowspan="8" width="15%" align="left" class="smallFont"> Each is worth 20% of overall grade</td>
        </tr>
        <tr class="bottom_border smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border smallFont">List Growth Last<br/> 90 Days</td>
            <td align="center" class="bottom_border smallFont smallFont"> &#8805; 10 </td>
            <td  align="center" class="shaded bottom_border smallFont smallFont">  &#8805; 8</td>
            <td align="center" class="bottom_border smallFont smallFont">  &#8805; 4 </td>
            <td class="shaded bottom_border smallFont smallFont" align="center">  &#8805; 1 </td>
            <td align="center" class="bottom_border smallFont smallFont"> 0 </td>
        </tr>
        <tr class=" smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border"> Percent Contacted</td>
            <td align="center" class="bottom_border smallFont">  &#8805; 50% </td>
            <td  align="center" class="shaded bottom_border smallFont">  &#8805; 35%</td>
            <td align="center" class="bottom_border smallFont">  &#8805; 20% </td>
            <td class="shaded bottom_border smallFont" align="center">  &#8805; 10%</td>
            <td align="center" class="bottom_border smallFont"> &#60; 10% </td>
        </tr>
        <tr class=" smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border">Open Rate</td>
            <td align="center" class="bottom_border smallFont"> &#8805; 35% </td>
            <td  align="center" class="shaded bottom_border smallFont"> &#8805; 25%</td>
            <td align="center" class="bottom_border smallFont"> &#8805; 15% </td>
            <td class="shaded bottom_border smallFont" align="center"> &#8805; 7% </td>
            <td align="center" class="bottom_border smallFont"> &#60; 7% </td>
        </tr>
        <tr class=" smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border">Click Through Rate</td>
            <td align="center" class="bottom_border smallFont"> &#8805; 20% </td>
            <td  align="center" class="shaded bottom_border smallFont"> &#8805; 10%</td>
            <td align="center" class="bottom_border smallFont">  &#8805; 5% </td>
            <td class="shaded bottom_border smallFont" align="center"> &#8805; 2% </td>
            <td align="center" class="bottom_border smallFont"> &#60; 2% </td>
        </tr>
        <tr class=" bottom_border smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border">Unsubscribe Percentage</td>
            <td align="center" class="bottom_border smallFont"> &#60; 2%</td>
            <td  align="center" class="shaded bottom_border smallFont"> &#60; 4%</td>
            <td align="center" class="bottom_border smallFont"> &#60; 6% </td>
            <td class="shaded bottom_border smallFont" align="center"> &#60; 8% </td>
            <td align="center" class="bottom_border smallFont"> &#8805; 8% </td>
        </tr>         
    </table>
    /-///////////////////////////////////////////////-/
    /-- The text should start here--/
/-///////////////////////////////////////////////////////////-/
    <p>
        The quick brown fox jumped over the lazy dog. 
    </p>
   
        

    <div style="page-break-after: always"></div>

 
I am trying to learn to write plugins for the Salesforce CLI. I have followed the directions to prepare your environment from the documentation (https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_plugins.meta/sfdx_cli_plugins/cli_plugins_generate_prepare.htm).  But  after I run sfdx plugins:generate I get the error 

AssertionError [ERR_ASSERTION]: Trying to copy from a source that does not exist: c:/Program Files (x86)/Salesforce CLI/client/node_modules/@salesforce/plugin-generator/templates/sfdxPlugin/test/tsconfig.json


I am assuming there is something wrong with my path or environment variables but I have not figured it out. I get the error in both Bash and the Windows Command Prompt.  Any help with getting this configured would be awesome. 
Is it possible to create a pie chart in VF  with slice labels that are different from the legend? In this chart I would like the labels to be the actual numbers and the legend to be text.  A pie wedge would have a label of 4% but the legend would say "Percent Opened" for example. 

Here is the page
<apex:page controller="CampaignPieChartController" title="Campaign Metrics" lightningStylesheets="true">
    <div class="slds-align_absolute-center">
        <apex:chart height="300" width="300" data="{!pieData}" resizable="true">
            <apex:legend position="right" font="14px Helvetica"/>
            <apex:pieSeries dataField="data" labelField="name"
                            colorSet="#008CC3,#F0B428,#B42846" donut="60">
                <apex:chartLabel display="middle" font="bold 14px Helvetica" orientation="vertical"/>
            </apex:pieSeries>
        </apex:chart>
    </div>
</apex:page>

Here is the controller

 
public without sharing class CampaignPieChartController {
	Id recId = ApexPages.currentPage().getParameters().get('Id');
	
	public List<PieWedgeData> getPieData()
	{
		
		List<PieWedgeData> data = new List<PieWedgeData>();
		List<Campaign> campaigns = new List<Campaign>();
		
		String sql = 'SELECT Emails_Delivered__c, Total_Opens__c, Total_Clicks__c FROM Campaign WHERE Campaign.Id =: recId';
		campaigns = Database.Query(sql);
		for(Campaign temp :campaigns)
		{
			data.add(new PieWedgeData('Delivered', temp.Emails_Delivered__c));
			data.add(new PieWedgeData('Opens', temp.Total_Opens__c));
			data.add(new PieWedgeData('Clicks', temp.Total_Clicks__c));
			
			
		}
		return data;
	}
	
	// Wrapper class
	public class PieWedgeData
	{
		public String name { get; set; }
		public Decimal data { get; set; }
		
		public PieWedgeData(String name, Decimal data)
		{
			this.name = name;
			this.data = data;
		}
	}

}

 
I have a simple Visualforce Pie Chart that I wanted to use in Lightning. When I add it to a record page the chart aligns left. I would like to be in the center but don't seem to be able to adjust it's positioning. Can this be done with CSS when it is being used on a Lightning  Record Page?
 
<apex:page controller="CampaignPieChartController" title="Campaign Metrics" lightningStylesheets="true">
   <div style="margin: 0px auto">
    <apex:chart height="300" width="300" data="{!pieData}" resizable="true">
        <apex:legend position="bottom" font="14px Helvetica"/>
        <apex:pieSeries dataField="data" labelField="name"
                        colorSet="#008CC3,#F0B428,#B42846">
        <apex:chartLabel display="outside" font="bold 18px Helvetica"/>
        </apex:pieSeries>
    </apex:chart>
    </div>
</apex:page>

 
Hi Friends. sorry to post such a blatant cry for help. But I can't this to work. I have a VF Page that renders as a PDF. I need to get the final  <td> in to align left and merge two rows so that the output is centered. Everything I ends up causing the entire page to fall apart. 

Here is a sample of a block I need to adjust. The final <td> That contains the <apex:outputText> should span two rows that the output can be centered vertically. 
 
<tr width="100%">
            <td width="25%" class="icon-label">
                <span class="icon-label">
                    Percent of Influencers Contacted
                </span>
            </td>
            <td width="50%" align="center">
                <apex:outputText value="{0, number, 0}%" style="font-size: 38px; font-weight: bold;
                                        font-family: SansSerif;
                                     color: {!if(Region__c.Percent_Influencers_Contacted__c >= 50, '#00a846',
                                     if(Region__c.Percent_Influencers_Contacted__c >= 35, '#aabb1a',
                                     if(Region__c.Percent_Influencers_Contacted__c >= 20,'#f0b428',
                                     if(Region__c.Percent_Influencers_Contacted__c >= 10, '#FF6428', '#B42846'))))}">

                    <apex:param value="{!FLOOR(Region__c.Percent_Influencers_Contacted__c)}"/>
                </apex:outputText>
            </td>
            <td width="25%">
            </td>
        </tr>
        <tr width="100%">
            <td width="25%" class="icon">
                <apex:image url="{!$Resource.icon_percent_contacted}" height="45" width="45"/>
            </td>
            <td width="50%" class="center_text">
                Percentage of total influencers who have received at
                least one email communication in the past 90 days
            </td>
            <td width="25%" align="center" class="grade_Output">
                <apex:outputText value="{!Region__c.Percent_Contacted_Grade__c}"
                                 style="font-size: 51px; font-weight: bold;
                                 margin-bottom: 20px; font-family: SansSerif;
                                     color: {!if(Region__c.percent_contacted_grade__c='A', '#00a846',
                                     if(Region__c.percent_contacted_grade__c ='B', '#aabb1a',
                                     if(Region__c.percent_contacted_grade__c ='C','#f0b428',
                                     if(Region__c.percent_contacted_grade__c ='D', '#FF6428', '#B42846'))))}"/>
            </td>
        </tr>
        <hr/>
The end state is the block where the letter F is right now should be centered vertically. 

User-added imageThank you for an
Hi Friends, working on my first and very simple Lightning Web Component. The LWC displays information about a parent record on the child record page.  That part is working fine.  But I would like the user to be able to click a button to go to the parent record. I think I have tried every possible permutation to try and pass the record id into the event handler and I can't seem to get it right. I am hoping someone can take a look this and tell me where I am going wrong with my event listener. 
Here is the button
<template>
    <lightning-card title="RelationshipOwner" icon-name="standard:partners">
        <lightning-button
                label="Go to Relationship Owner Record"
                onclick={navigateToOwner}
                class="slds-m-right_x-small"
        ></lightning-button>
Here is the JS
 
/**
 * Created by Admin on 2/14/2019.
 */

import { LightningElement, api, wire } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import Owner_Id from '@salesforce/schema/Contact.New_Relationship_owner1__c';
const owner_fields = [Owner_Id];
export default class relationshipowner extends NavigationMixin(LightningElement) {
@api recordId; // relationship owner id
@wire(getRecord, { recordId: '$recordId', fields: owner_fields })
    contact;
    navigateToOwner() {
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: Owner_Id,
                objectApiName: 'relationship_owner__c',
                actionName: 'view'
            }
        });
    }
    get ownerId() {
        return getFieldValue(this.contact.data, Owner_Id);
    }


}


 
Hello Friends,

I have a method that is called from my Campaign Member Trigger Handler.  If a Campaign member's status changes to "Opened" then  Email Opened__c field on the contact object should be incremented by one.  It is working in the UI. But I can not get my test classes to pass. It seems that no matter how I try to change the Campaign Member Status in the test my System.debug  messages read as "Status = Sent." Any help would be much appreciated. 

Here are the methods. 
public with sharing class CampaignMemberUtils {
	
	public static void   main(List<CampaignMember> newList, Map<Id, CampaignMember> oldList){
		//if the contact status has changed and is opened or clicked call score method
		
		Set<Id> contactIds  = new Set<Id>();
		
		for (CampaignMember c : newList){
			CampaignMember oldMember = oldList.get(c.Id);
			System.debug('Email status is :' + c.Status);
			if (c.Status == 'Opened' && oldMember.Status != 'Opened'){
				contactIds.add(c.ContactId);
			}
		}
		System.debug('contactsToProcess.Size() = ' + contactIds.size());
			List<Contact> contacts = getContacts(contactIds);
			updateContactOpenScores(contacts);
		
	}
	public static void updateContactOpenScores(List<Contact> contacts){
			System.debug('Number of contacts passed to update open score method = ' + contacts.size());
			List<Contact> contactsToUpdate = new List<Contact>();
			for(Contact c : contacts){
				c.Pardot_Emails_Opened__c  +=1;
				contactsToUpdate.add(c);
			}
			update contactsToUpdate;
		}
	public static List<Contact> getContacts(Set<Id> ids) {
		List<Contact> contacts = [
				SELECT Id, Pardot_Emails_Opened__c, Pardot_Links_Clicked__c
				FROM Contact
				WHERE Id = :ids
		];
		return contacts;
	}
}

And here is my test class 
@IsTest public static void singleRecordFound(){
		Account a = new Account(Name = 'Test Acc');
		insert a;
		Contact c = new Contact(LastName = 'Test Contact', AccountId = a.Id, Pardot_Emails_Opened__c = 0);
		insert c;
		Campaign campaign = new Campaign(Name = 'Test Campaign', IsActive = true);
		insert campaign;
		CampaignMemberStatus  status = new CampaignMemberStatus(CampaignId = campaign.Id, Label = 'Opened');
		insert status;
		CampaignMember campaignMember = new CampaignMember(CampaignId = campaign.Id, ContactId = c.Id);
		insert campaignMember;
		CampaignMember updatedCampaignMember = [SELECT Id, Status FROM CampaignMember LIMIT 1];
		updatedCampaignMember.Status = 'Opened';
		update campaignMember;
		Contact updatedContact = [SELECT Id, Pardot_Emails_Opened__c FROM Contact LIMIT 1];
		
		System.assertEquals(1, updatedContact.Pardot_Emails_Opened__c);
	}

 
Hi Friends,  I have a method getPardotTaskCount() that is called from a trigger handler.  It is designed to take the count of all tasks associated with a contact ID  that meet certain criteria and update a number field.  For the life of me, I can't get it to work right. I have put System.debug statements everywhere. When I test from the UI all the values are correct but the field does not get updated. In my test class, the assertions also fail.  I would appreciate a second set of eyes. I am sure  I am missing something simple.
The method
public static void getPardotTaskCount(Set<Id> contactIds){
        System.debug('GetpardotTaskCount method called, contactIds.size() = ' + contactIds.size());

        //loop through the Contact Ids and get all tasks where Who Id = Contact ID
        //Then update the Contact Total emails field
        List<Contact> contacts = [SELECT Id, Total_Emails_Sent__c FROM Contact
                                    WHERE Id =: contactIds];
        Map<Id, AggregateResult> aggregateResultMap = new Map<Id, AggregateResult>([SELECT WhoId Id, COUNT(Subject) subjectCount
        From Task
        WHERE WhoId =: contactIds
        AND Subject LIKE '%Pardot%'
        AND WhoId != null
        GROUP BY WhoId
        ALL ROWS
        ]);
        System.debug('subjectCount.values() = ' +  aggregateResultMap.Values());
        for(Contact c : contacts){
            if (aggregateResultMap.containsKey(c.Id)) {
                System.debug('Contained  Contact Key branch of If Statement');
                c.Total_Emails_Sent__c = Integer.valueOf(aggregateResultMap.get(c.Id).get('subjectCount'));
            }else {
                c.Total_Emails_Sent__c = 0;
            }
        }
    }
The Test 
@IsTest
    public static void testPardotEmailCount(){
        //Given
        Account acc = new Account(Name = 'Test Acc');
        Insert acc;
        Integer numTasks = 1;
        List<Task> tasks = new List<Task>();
        Contact contact = new Contact(LastName = 'Test Influencer', AccountId = acc.Id);
        insert contact;
        for (Integer i = 0; i < numTasks; i++){
            Task t = new Task(Subject = 'Pardot List Email ' + String.valueOf(i), WhoId = contact.Id);
            tasks.add(t);
        }
        insert tasks;
        Contact updatedContact = [SELECT Id, Total_Emails_Sent__c FROM Contact LIMIT 1];
        //then
        System.assertEquals(1, updatedContact.Total_Emails_Sent__c);

    }




 
Hi Friends I have a form that I need to write in Visualforce because it must be exportable to PDF. I  was using CSS Grid for my layout but when I switched to renderAs="PDF" my grid formatting was gone. If I add floats the PDF responds. Am I a making a mistake or does the  CSS Grid not work with the PDF? Here is my <head> 
 
<apex:page id="Region_Health_Check" showHeader="false" standardController="Region__c" docType="html-5.0"
    sideBar="false" standardStylesheets="false" renderAs="pdf">
    <head>
        <title>Region Health Check Report</title>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <apex:stylesheet value="{!$Resource.HealthCheckStyle}"/>
    </head>

CSS forgive having floats and grid in place. 
/* HealthCheckStyle */
@page{
    size: letter;
    margin: 25mm;

}

body{
    font-family:  BrownStd,serif;
    font-size: 14px;
    display: grid;
}
.top{
    display: grid;
    grid-template-columns: repeat(10, 10%);
    grid-template-rows: auto;
}
.score-label{
    grid-area: 1 / 9/ 2 / 10;
    font-size:  12px;
    float: right;
}
.engagement-label{
    grid-area:  2 / 1/  2 /4;
    font-size: 26px;
    font-weight: bold;
}
.final-grade{
    font-size: 39px;
    font-weight: bold;
    grid-area: 2/9/4/10;
    float: right;
}
.region-name{
    font-size: 24px;
    grid-area: 3/ 1/ 4/ 3;
}
hr {
    display: block;
    height: 1px;
    border: 0;
    border-top: 1px solid red;
    margin: 1em 0;
    padding: 0;
}
h4{
    font-size: 14px;
}

 
Hi Friends,

I have a requirement to find all contacts with no related tasks or if they do have a task to filter out certain types.  When I start with a base SOQL Query on the workbench I get an error that Task is not supported from Semi Join inner select.  The base query is:  

SELECT Id, Name FROM Contact WHERE Id NOT IN (SELECT WhoID FROM Task). Is there another way to do this? 
Hi Friends,

I have a method that updates a lookup field on the task object. The task field is updated based on the value in a lookup field on the Contact. I  know it is inefficient and it fails my bulk test class. But I am not sure how to optimize the SOQL query to get my code under the  100 SOQL query limit. Any tips or pointers would be great.  The tasks are getting passed into the Method through trigger.new in a trigger handler. I am sure that putting the WhoIds into a list and doing a query to get the contacts and add them to a Map is pretty sub-optimal. 
public static void assignTasksToRelationshipOwnersInsert(List<Task> taskList) {
        //assign contacts owner to task look up field
        Set<Id> contactIds = new Set<Id>();
        for (Task t : taskList) {
            if (t.WhoId != null && t.Subject.contains('Pardot List Email')) {
                contactIds.add(t.WhoId);
            }
        }
        //create a map of contacts and regions
        //Fails SOQL limit here
        List<Contact> contactList = [
                SELECT Id, New_Relationship_owner1__c
                FROM CONTACT
                WHERE Id IN:contactIds
                AND New_Relationship_owner1__c != Null
        ];
        Map<Id, ID> contactMap = new Map<Id, Id>();
        for (Contact c : contactList) {
            contactMap.put(c.Id, c.New_Relationship_owner1__c);
        }
        for (Task updatedTask : taskList) {
            if (contactMap.containsKey(updatedTask.WhoId) && contactMap.size() > 0) {
                updatedTask.Relationship_Owner__c = contactMap.get(updatedTask.WhoId);
            }
        }
    }


 
Hi Friends, 

I know null pointer errors are such a common question I hate to add another one. But I can't figure out what I am doing wrong and I am hoping I can learn something here.  I'm getting the error from my final For Loop. I thought I had checked for it with the != null in my If statement. Hoping someone can point me in the right direction.
 
public  class UniqueEmailCountHandler {
    
    public static void uniqueRelationshipOwnerEmails(List<relationship_owner__c> roList){
        //count the unique emails  that have been sent by a relationship owner
        // add all contacts associated with relationship owner to map.         
        Map<id, Contact> contactMap = new Map<Id, Contact>([SELECT Id,
                                                            New_Relationship_Owner1__c
                                                            FROM Contact
                                                            WHERE New_Relationship_owner1__c IN : roList]);
        system.debug('Number of relationship owners in trigger = ' + roList.size());
        system.debug('Contacts found = ' + contactMap.size());
        //put tasks where whoId is in the contact map into a new map
        List<Task> taskList = [SELECT Id, WhoId,Subject
                               FROM Task 
                               WHERE WhoId IN :contactMap.keySet()
                               AND Subject LIKE '%Pardot List %'];
        system.debug('Tasks Found  and added to map = ' + taskList.size());
        
        //use set to dedupe the list
        Map<Id, Set<String>> subjectLineMap = new Map<Id, Set<String>>();
        
        for(task t : taskList){
            Id ownerId = contactMap.get(t.WhoId).New_Relationship_Owner1__c;            
            if(!subjectLineMap.containsKey(ownerId)){
                subjectLineMap.put(ownerId, new Set<String>());
                system.debug('Subect Line found ' + t.Subject);              
                
            }
            Set<String> subjects = subjectLineMap.get(OwnerId);
            subjects.add(t.Subject);
            subjectLineMap.put(OwnerId, Subjects);
            
        }
        system.debug('Map size   =' + subjectLineMap.size());
        system.debug('map values =' + subjectLineMap.values());
        system.debug('map keys   =' + subjectLineMap.Keyset());
        {
            for(relationship_owner__c relationshipOwner : roList){
                if(subjectLIneMap.get(relationshipOwner.Id).size() != Null){
                relationshipOwner.Unique_Emails_Sent__c = subjectLIneMap.get(relationshipOwner.Id).size();
                }
                
            }

 
Hi Friends,

Getting some weird errors when I try to run package:version: create

The classes that are being listed in the errors are in another package. The dependency is defined in the JSON and I  updated this package version today. Any thoughts on what would be going wrong here?

Short of just removing all the dependencies and starting over.
 
ContactStatusManager_Test: Variable does not exist: TestDataFactory,AppSwitcher: An unexpected error occurred. Please include this Err
orId if you contact support: 169023167-52320 (442557440),Admin: In field: apexClass - no ApexClass named CampaignMemberStatusFactory found,CampaignMemberStatusTriggerHandler: Depe
ndent class is invalid and needs recompilation:
 Class CampaignMemberStatusFactory : Variable does not exist: RecordTypeSelector,CampaignMemberStatusFactory: Variable does not exist: RecordTypeSelector,ContactStatusManager_Test
: Variable does not exist: TestDataFactory

 
Hi Friends,

Far from a LWC expert here. and trying to get a Lightning Data Table that is sortable. I feel like I have followed everything in the documentation but when I click the arrow in the table header nothing happens. 

Here is my JS
import { LightningElement, track, wire, api } from 'lwc';
import getRecords from '@salesforce/apex/NewToLiftController.getRecords';
import { getRecord } from 'lightning/uiRecordApi';
import { NavigationMixin } from 'lightning/navigation';

const columns = [
    { label: 'First Name', fieldName: 'FirstName', type: "Text", sortable: true},
    { label: 'Last Name', fieldName: 'LastName', type: "Text", sortable: true },
    { label: 'Email', fieldName: 'Email', type: 'Email', sortable: true },
    { label: 'Role', fieldName: 'Role__c', type: 'Text', sortable: true },
    { label: 'Startup Leadership', fieldName: 'Startup_Leadership__c', type: 'boolean', sortable: true },
    { label: 'Company', fieldName: 'CompanyOrAccount', type: 'Text', sortable: true },
];

export default class DatatableBasic extends LightningElement {
@api recordId;
@track data = [];
@track columns = columns;
@track tableLoadingState = true;
@track rowOffset = 0;

@ wire(getRecords, {recordId: '$recordId'})
    wiredRecordsMethod({error, data}) {
        if (data) {this.data = data;
            this.error = undefined;
        } else if (error) {
            this.error = error;
            this.data = undefined;
        }
        this.tableLoadingState = false;
    }
    increaseRowOffset(){this.rowOffset += 1;
    }
    // The method onsort event handler
    updateColumnSorting(event) {
        var fieldName = event.detail.fieldName;
        var sortDirection = event.detail.sortDirection;
        // assign the latest attribute with the sorted column fieldName and sorted direction
        this.sortedBy = fieldName;
        this.sortedDirection = sortDirection;
        this.data = this.sortData(fieldName, sortDirection);        
    }
}
And here is the HTML
 
<template>
            <lightning-card title='First Time Campaign Memebers' icon-name="standard:contact">
                <lightning-datatable
                        key-field="id"
                        data={data}
                        show-row-number-column
                        row-number-offset={rowOffset}
                        hide-checkbox-column
                        columns={columns}
                        sorted-by={sortedBy}
                        sorted-direction={sortedDirection}
                        onsort={updateColumnSorting}
                        is-loading={tableLoadingState}>
                </lightning-datatable>
            </lightning-card>
</template>

 
I have a Visual Force Page that renders as a PDF. I need to add some text to the first page.  It should be below the last </table> tag. But it keeps appearing at the top of the table.  I have marked it with comments to show where it is supposed to appear and where it actually shows up on the PDF. Any help with this formatting would be great. 
 
<div style="margin-bottom: 0; padding-bottom: 0">
        <p class="smallFont" style="margin-bottom: 0; padding-bottom: 0">
            The Program Performance Scorecard is a tool by which you can monitor the overall health of your region’s Influencer list.
            The factors that contribute to the overall health grade are listed below. Each category is worth 20% of the grade.
            Your grades are on page 2. This scorecard should be used in conjunction with the internal benchmarks and optimization guidelines to identify areas
            of opportunity and to inform your influencer program strategy.
        </p>
    </div>
/-//////////////////////////////////////////////////////////////////////////////-/
    /--But instead the text always shows up here --/
/-/////////////////////////////////////////////////////////////////////////////-/

    <table width="100%"    class="score_table smallFont" cellspacing="0">
        <tr width="100%"   class="darkBottomBorder smallFont">
            <th colspan="2"    class="darkBottomBorder smallFont" id="scoringConvention"> Scoring Convention </th>
            <th align="center" class="darkBottomBorder a_Color "> A</th>
            <th align="center" class="darkBottomBorder b_Color"> B</th>
            <th align="center" class="darkBottomBorder c_Color"> C</th>
            <th align="center" class="darkBottomBorder d_Color"> D</th>
            <th align="center" class="darkBottomBorder f_Color"> F</th>
        </tr>
        <tr width="15%" class="font smallFont">
            <td rowspan="8" width="15%" align="left" class="smallFont"> Each is worth 20% of overall grade</td>
        </tr>
        <tr class="bottom_border smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border smallFont">List Growth Last<br/> 90 Days</td>
            <td align="center" class="bottom_border smallFont smallFont"> &#8805; 10 </td>
            <td  align="center" class="shaded bottom_border smallFont smallFont">  &#8805; 8</td>
            <td align="center" class="bottom_border smallFont smallFont">  &#8805; 4 </td>
            <td class="shaded bottom_border smallFont smallFont" align="center">  &#8805; 1 </td>
            <td align="center" class="bottom_border smallFont smallFont"> 0 </td>
        </tr>
        <tr class=" smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border"> Percent Contacted</td>
            <td align="center" class="bottom_border smallFont">  &#8805; 50% </td>
            <td  align="center" class="shaded bottom_border smallFont">  &#8805; 35%</td>
            <td align="center" class="bottom_border smallFont">  &#8805; 20% </td>
            <td class="shaded bottom_border smallFont" align="center">  &#8805; 10%</td>
            <td align="center" class="bottom_border smallFont"> &#60; 10% </td>
        </tr>
        <tr class=" smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border">Open Rate</td>
            <td align="center" class="bottom_border smallFont"> &#8805; 35% </td>
            <td  align="center" class="shaded bottom_border smallFont"> &#8805; 25%</td>
            <td align="center" class="bottom_border smallFont"> &#8805; 15% </td>
            <td class="shaded bottom_border smallFont" align="center"> &#8805; 7% </td>
            <td align="center" class="bottom_border smallFont"> &#60; 7% </td>
        </tr>
        <tr class=" smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border">Click Through Rate</td>
            <td align="center" class="bottom_border smallFont"> &#8805; 20% </td>
            <td  align="center" class="shaded bottom_border smallFont"> &#8805; 10%</td>
            <td align="center" class="bottom_border smallFont">  &#8805; 5% </td>
            <td class="shaded bottom_border smallFont" align="center"> &#8805; 2% </td>
            <td align="center" class="bottom_border smallFont"> &#60; 2% </td>
        </tr>
        <tr class=" bottom_border smallFont" width="100%" align="right">
            <td align="left" class="shaded bottom_border">Unsubscribe Percentage</td>
            <td align="center" class="bottom_border smallFont"> &#60; 2%</td>
            <td  align="center" class="shaded bottom_border smallFont"> &#60; 4%</td>
            <td align="center" class="bottom_border smallFont"> &#60; 6% </td>
            <td class="shaded bottom_border smallFont" align="center"> &#60; 8% </td>
            <td align="center" class="bottom_border smallFont"> &#8805; 8% </td>
        </tr>         
    </table>
    /-///////////////////////////////////////////////-/
    /-- The text should start here--/
/-///////////////////////////////////////////////////////////-/
    <p>
        The quick brown fox jumped over the lazy dog. 
    </p>
   
        

    <div style="page-break-after: always"></div>

 
I am trying to learn to write plugins for the Salesforce CLI. I have followed the directions to prepare your environment from the documentation (https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_plugins.meta/sfdx_cli_plugins/cli_plugins_generate_prepare.htm).  But  after I run sfdx plugins:generate I get the error 

AssertionError [ERR_ASSERTION]: Trying to copy from a source that does not exist: c:/Program Files (x86)/Salesforce CLI/client/node_modules/@salesforce/plugin-generator/templates/sfdxPlugin/test/tsconfig.json


I am assuming there is something wrong with my path or environment variables but I have not figured it out. I get the error in both Bash and the Windows Command Prompt.  Any help with getting this configured would be awesome. 
I have a simple Visualforce Pie Chart that I wanted to use in Lightning. When I add it to a record page the chart aligns left. I would like to be in the center but don't seem to be able to adjust it's positioning. Can this be done with CSS when it is being used on a Lightning  Record Page?
 
<apex:page controller="CampaignPieChartController" title="Campaign Metrics" lightningStylesheets="true">
   <div style="margin: 0px auto">
    <apex:chart height="300" width="300" data="{!pieData}" resizable="true">
        <apex:legend position="bottom" font="14px Helvetica"/>
        <apex:pieSeries dataField="data" labelField="name"
                        colorSet="#008CC3,#F0B428,#B42846">
        <apex:chartLabel display="outside" font="bold 18px Helvetica"/>
        </apex:pieSeries>
    </apex:chart>
    </div>
</apex:page>

 
Hi Friends. sorry to post such a blatant cry for help. But I can't this to work. I have a VF Page that renders as a PDF. I need to get the final  <td> in to align left and merge two rows so that the output is centered. Everything I ends up causing the entire page to fall apart. 

Here is a sample of a block I need to adjust. The final <td> That contains the <apex:outputText> should span two rows that the output can be centered vertically. 
 
<tr width="100%">
            <td width="25%" class="icon-label">
                <span class="icon-label">
                    Percent of Influencers Contacted
                </span>
            </td>
            <td width="50%" align="center">
                <apex:outputText value="{0, number, 0}%" style="font-size: 38px; font-weight: bold;
                                        font-family: SansSerif;
                                     color: {!if(Region__c.Percent_Influencers_Contacted__c >= 50, '#00a846',
                                     if(Region__c.Percent_Influencers_Contacted__c >= 35, '#aabb1a',
                                     if(Region__c.Percent_Influencers_Contacted__c >= 20,'#f0b428',
                                     if(Region__c.Percent_Influencers_Contacted__c >= 10, '#FF6428', '#B42846'))))}">

                    <apex:param value="{!FLOOR(Region__c.Percent_Influencers_Contacted__c)}"/>
                </apex:outputText>
            </td>
            <td width="25%">
            </td>
        </tr>
        <tr width="100%">
            <td width="25%" class="icon">
                <apex:image url="{!$Resource.icon_percent_contacted}" height="45" width="45"/>
            </td>
            <td width="50%" class="center_text">
                Percentage of total influencers who have received at
                least one email communication in the past 90 days
            </td>
            <td width="25%" align="center" class="grade_Output">
                <apex:outputText value="{!Region__c.Percent_Contacted_Grade__c}"
                                 style="font-size: 51px; font-weight: bold;
                                 margin-bottom: 20px; font-family: SansSerif;
                                     color: {!if(Region__c.percent_contacted_grade__c='A', '#00a846',
                                     if(Region__c.percent_contacted_grade__c ='B', '#aabb1a',
                                     if(Region__c.percent_contacted_grade__c ='C','#f0b428',
                                     if(Region__c.percent_contacted_grade__c ='D', '#FF6428', '#B42846'))))}"/>
            </td>
        </tr>
        <hr/>
The end state is the block where the letter F is right now should be centered vertically. 

User-added imageThank you for an
Hello Friends,

I have a method that is called from my Campaign Member Trigger Handler.  If a Campaign member's status changes to "Opened" then  Email Opened__c field on the contact object should be incremented by one.  It is working in the UI. But I can not get my test classes to pass. It seems that no matter how I try to change the Campaign Member Status in the test my System.debug  messages read as "Status = Sent." Any help would be much appreciated. 

Here are the methods. 
public with sharing class CampaignMemberUtils {
	
	public static void   main(List<CampaignMember> newList, Map<Id, CampaignMember> oldList){
		//if the contact status has changed and is opened or clicked call score method
		
		Set<Id> contactIds  = new Set<Id>();
		
		for (CampaignMember c : newList){
			CampaignMember oldMember = oldList.get(c.Id);
			System.debug('Email status is :' + c.Status);
			if (c.Status == 'Opened' && oldMember.Status != 'Opened'){
				contactIds.add(c.ContactId);
			}
		}
		System.debug('contactsToProcess.Size() = ' + contactIds.size());
			List<Contact> contacts = getContacts(contactIds);
			updateContactOpenScores(contacts);
		
	}
	public static void updateContactOpenScores(List<Contact> contacts){
			System.debug('Number of contacts passed to update open score method = ' + contacts.size());
			List<Contact> contactsToUpdate = new List<Contact>();
			for(Contact c : contacts){
				c.Pardot_Emails_Opened__c  +=1;
				contactsToUpdate.add(c);
			}
			update contactsToUpdate;
		}
	public static List<Contact> getContacts(Set<Id> ids) {
		List<Contact> contacts = [
				SELECT Id, Pardot_Emails_Opened__c, Pardot_Links_Clicked__c
				FROM Contact
				WHERE Id = :ids
		];
		return contacts;
	}
}

And here is my test class 
@IsTest public static void singleRecordFound(){
		Account a = new Account(Name = 'Test Acc');
		insert a;
		Contact c = new Contact(LastName = 'Test Contact', AccountId = a.Id, Pardot_Emails_Opened__c = 0);
		insert c;
		Campaign campaign = new Campaign(Name = 'Test Campaign', IsActive = true);
		insert campaign;
		CampaignMemberStatus  status = new CampaignMemberStatus(CampaignId = campaign.Id, Label = 'Opened');
		insert status;
		CampaignMember campaignMember = new CampaignMember(CampaignId = campaign.Id, ContactId = c.Id);
		insert campaignMember;
		CampaignMember updatedCampaignMember = [SELECT Id, Status FROM CampaignMember LIMIT 1];
		updatedCampaignMember.Status = 'Opened';
		update campaignMember;
		Contact updatedContact = [SELECT Id, Pardot_Emails_Opened__c FROM Contact LIMIT 1];
		
		System.assertEquals(1, updatedContact.Pardot_Emails_Opened__c);
	}

 
Hi Friends,  I have a method getPardotTaskCount() that is called from a trigger handler.  It is designed to take the count of all tasks associated with a contact ID  that meet certain criteria and update a number field.  For the life of me, I can't get it to work right. I have put System.debug statements everywhere. When I test from the UI all the values are correct but the field does not get updated. In my test class, the assertions also fail.  I would appreciate a second set of eyes. I am sure  I am missing something simple.
The method
public static void getPardotTaskCount(Set<Id> contactIds){
        System.debug('GetpardotTaskCount method called, contactIds.size() = ' + contactIds.size());

        //loop through the Contact Ids and get all tasks where Who Id = Contact ID
        //Then update the Contact Total emails field
        List<Contact> contacts = [SELECT Id, Total_Emails_Sent__c FROM Contact
                                    WHERE Id =: contactIds];
        Map<Id, AggregateResult> aggregateResultMap = new Map<Id, AggregateResult>([SELECT WhoId Id, COUNT(Subject) subjectCount
        From Task
        WHERE WhoId =: contactIds
        AND Subject LIKE '%Pardot%'
        AND WhoId != null
        GROUP BY WhoId
        ALL ROWS
        ]);
        System.debug('subjectCount.values() = ' +  aggregateResultMap.Values());
        for(Contact c : contacts){
            if (aggregateResultMap.containsKey(c.Id)) {
                System.debug('Contained  Contact Key branch of If Statement');
                c.Total_Emails_Sent__c = Integer.valueOf(aggregateResultMap.get(c.Id).get('subjectCount'));
            }else {
                c.Total_Emails_Sent__c = 0;
            }
        }
    }
The Test 
@IsTest
    public static void testPardotEmailCount(){
        //Given
        Account acc = new Account(Name = 'Test Acc');
        Insert acc;
        Integer numTasks = 1;
        List<Task> tasks = new List<Task>();
        Contact contact = new Contact(LastName = 'Test Influencer', AccountId = acc.Id);
        insert contact;
        for (Integer i = 0; i < numTasks; i++){
            Task t = new Task(Subject = 'Pardot List Email ' + String.valueOf(i), WhoId = contact.Id);
            tasks.add(t);
        }
        insert tasks;
        Contact updatedContact = [SELECT Id, Total_Emails_Sent__c FROM Contact LIMIT 1];
        //then
        System.assertEquals(1, updatedContact.Total_Emails_Sent__c);

    }




 
Hi Friends,

I have a method that updates a lookup field on the task object. The task field is updated based on the value in a lookup field on the Contact. I  know it is inefficient and it fails my bulk test class. But I am not sure how to optimize the SOQL query to get my code under the  100 SOQL query limit. Any tips or pointers would be great.  The tasks are getting passed into the Method through trigger.new in a trigger handler. I am sure that putting the WhoIds into a list and doing a query to get the contacts and add them to a Map is pretty sub-optimal. 
public static void assignTasksToRelationshipOwnersInsert(List<Task> taskList) {
        //assign contacts owner to task look up field
        Set<Id> contactIds = new Set<Id>();
        for (Task t : taskList) {
            if (t.WhoId != null && t.Subject.contains('Pardot List Email')) {
                contactIds.add(t.WhoId);
            }
        }
        //create a map of contacts and regions
        //Fails SOQL limit here
        List<Contact> contactList = [
                SELECT Id, New_Relationship_owner1__c
                FROM CONTACT
                WHERE Id IN:contactIds
                AND New_Relationship_owner1__c != Null
        ];
        Map<Id, ID> contactMap = new Map<Id, Id>();
        for (Contact c : contactList) {
            contactMap.put(c.Id, c.New_Relationship_owner1__c);
        }
        for (Task updatedTask : taskList) {
            if (contactMap.containsKey(updatedTask.WhoId) && contactMap.size() > 0) {
                updatedTask.Relationship_Owner__c = contactMap.get(updatedTask.WhoId);
            }
        }
    }


 
Hi Friends, 

I know null pointer errors are such a common question I hate to add another one. But I can't figure out what I am doing wrong and I am hoping I can learn something here.  I'm getting the error from my final For Loop. I thought I had checked for it with the != null in my If statement. Hoping someone can point me in the right direction.
 
public  class UniqueEmailCountHandler {
    
    public static void uniqueRelationshipOwnerEmails(List<relationship_owner__c> roList){
        //count the unique emails  that have been sent by a relationship owner
        // add all contacts associated with relationship owner to map.         
        Map<id, Contact> contactMap = new Map<Id, Contact>([SELECT Id,
                                                            New_Relationship_Owner1__c
                                                            FROM Contact
                                                            WHERE New_Relationship_owner1__c IN : roList]);
        system.debug('Number of relationship owners in trigger = ' + roList.size());
        system.debug('Contacts found = ' + contactMap.size());
        //put tasks where whoId is in the contact map into a new map
        List<Task> taskList = [SELECT Id, WhoId,Subject
                               FROM Task 
                               WHERE WhoId IN :contactMap.keySet()
                               AND Subject LIKE '%Pardot List %'];
        system.debug('Tasks Found  and added to map = ' + taskList.size());
        
        //use set to dedupe the list
        Map<Id, Set<String>> subjectLineMap = new Map<Id, Set<String>>();
        
        for(task t : taskList){
            Id ownerId = contactMap.get(t.WhoId).New_Relationship_Owner1__c;            
            if(!subjectLineMap.containsKey(ownerId)){
                subjectLineMap.put(ownerId, new Set<String>());
                system.debug('Subect Line found ' + t.Subject);              
                
            }
            Set<String> subjects = subjectLineMap.get(OwnerId);
            subjects.add(t.Subject);
            subjectLineMap.put(OwnerId, Subjects);
            
        }
        system.debug('Map size   =' + subjectLineMap.size());
        system.debug('map values =' + subjectLineMap.values());
        system.debug('map keys   =' + subjectLineMap.Keyset());
        {
            for(relationship_owner__c relationshipOwner : roList){
                if(subjectLIneMap.get(relationshipOwner.Id).size() != Null){
                relationshipOwner.Unique_Emails_Sent__c = subjectLIneMap.get(relationshipOwner.Id).size();
                }
                
            }

 
Hello Friends. 

I am hoping someone can help me with this method. I have been working on it all afternoon with no luck.  My requirement is to get to a  count of tasks that are related to contacts and place a value on a custom object. The custom object relationship_owner__C is the parent in a  look up a relationship with the Contact object. 

When a relationship_owner__C is updated then look for all contacts owned by the relationship owner with tasks that begin with the phrase "Pardot List" Evaluate the text that comes after Pardot list to determine how many unique subject lines there are. 

If the relationship owner  Test Owner has 5 contacts and Each Contact has Two Tasks with the Subject Line Pardot List 1 and Pardot List 2. The relationship owner would be updated with a  total unique value of 2.  When I test in the UI I get a value of 1 no matter how many tasks I create. And my test class for a single email fails its assertions and says 0 emails.

Here is my method.  It is called from a trigger handler on before update. 
public static void uniqueRelationshipOwnerEmails(List<relationship_owner__c> roList){
        //count the unique emails  that have been sent by a relationship owner
        // add all contacts associated with relationship owner to map.         
        Map<id, Contact> contactMap = new Map<Id, Contact>([SELECT Id,
                                                            New_Relationship_Owner1__c
                                                            FROM Contact
                                                            WHERE New_Relationship_owner1__c IN : roList]);
        system.debug('Number of relationship owners in trigger = ' + roList.size());
        system.debug('Contacts found = ' + contactMap.size());
        //put tasks where whoId is in the contact map into a new map
        List<Task> taskList = [SELECT Id, WhoId,Subject
                               FROM Task 
                               WHERE WhoId IN :contactMap.keySet()
                               AND Subject LIKE '%Pardot List %'];
        system.debug('Tasks Found  and added to map = ' + taskList.size());
        
        //use set to dedupe the list
        Map<Id, Set<String>> subjectLineMap = new Map<Id, Set<String>>();
        
        for(task t : taskList){
            Id ownerId = contactMap.get(t.WhoId).New_Relationship_Owner1__c;            
            if(!subjectLineMap.containsKey(ownerId)){
                subjectLineMap.put(ownerId, new Set<String>());
                system.debug('Subect Line found ' + t.Subject);
               
                
            }