Sharepoint Development
Sharepoint Development
SharePoint development
SharePoint Framework
Getting started
Set up Office 365 tenant
Set up development environment
Web parts
Getting started
Build your first web part
Connect your web part to SharePoint
Deploy your web part to a SharePoint page
Host your web part from Office 365 CDN
Add jQueryUI Accordion to your web part
Use Office UI Fabric React components in your web part
Provision assets from your web part
Deploy your web part to an Azure CDN
Basics
Integrate properties with SharePoint
Configure custom properties
Configure web part icon
Using full-width column
Hide from the toolbox
Preconfigure web parts
Validate properties
Share data between web parts
Tutorial
Extend property pane
Build custom controls
Use cascading dropdowns
Migrate existing customizations
Script Editor web part
jQuery and DataTables
jQuery and FullCalendar
AngularJS applications
Work with __REQUESTDIGEST
Use JSOM
Extensions
Getting started
Build your first extension
Use page placeholders
Deploy your extension to SharePoint
Host extension from CDN
Build Field Customizer
Build ListView Command Set
Configure extension icon
Migrate existing customizations
Client Side Rendering (JSLink)
JavaScript embedding (UserCustomAction)
Edit Control Block (ECB) menu item tutorial
Client Side Rendering (JSLink) tutorial
JavaScript embedding (UserCustomAction) tutorial
Guidance
Enterprise guidance
Team-based development
Governance considerations
Connecting components
External libraries
Add external libraries
JavaScript libraries
CSS styles
SP PnP JS
AngularJS
Connect to APIs
Connect to APIs secured with Azure AD
Call the Microsoft Graph API using OAuth
Connect to APIs secured with Azure AD using the AadHttpClient
Consume enterprise APIs (tutorial)
Consume multi-tenant enterprise APIs (tutorial)
Microsoft Graph
Consume Microsoft Graph (tutorial)
Microsoft GraphHttpClient (Deprecated)
Tutorial (Deprecated)
Setup and deployment
Package solution
Custom build tasks
Extend Webpack
Update packages
Tenant-scoped solution deployment
Tenant properties
Provision SharePoint assets
Optimize builds for production
Localize web parts
SharePoint 2016 support
Use preview capabilities
Design
Design a web part
Reactive and nonreactive web parts
Responsive design
Titles and descriptions
Commanding within a web part
UI text
Placeholders and fallbacks
Empty state of a web part
Accessibility
Key web part examples
Web part showcase
Authoring pages
Design considerations
Custom dialogs
Work with CSS
Themes and colors
Use themes
Office UI Fabric integration
Tools and libraries
Toolchain
Yeoman generator
Debugging
Debug in Visual Studio Code
Debug on modern pages
Roadmap
Known issues and FAQ
Features
Connect to Office 365 group
CSOM development
Hub sites
Create hub sites with PowerShell
PowerShell cmdlets for hub sites
REST API
SP.HubSites.CanCreate
GetById
HubSiteData
HubSites
JoinHubSite
RegisterHubSite
SyncHubSiteTheme
UnRegisterHubSite
SPHubSite type
SPHubSiteData type
SharePoint APIs
SharePoint .NET Server, CSOM, JSOM, and REST API index
Complete basic operations using SharePoint client library code
Complete basic operations using JavaScript library code in SharePoint
Get to know the SharePoint REST service
Complete basic operations
Work with lists and list items
Work with folders and files
Determine endpoint URIs
Use OData query operations
Navigate data structure
Synchronize items
Upload a file
Set custom permissions
Make batch requests
Migration API
Azure container and queue
Encryption
Throttling
Sharing
Site design
Get started
Set scope
Customize default design
JSON schema reference
PowerShell cmdlets
REST API
PnP provisioning engine
Site theming
JSON schema reference
PowerShell cmdlets
CSOM API
REST API
Webhooks
Get started
Reference implementation
Use Azure Functions
List webhooks
Create subscription
Update subscription
Delete subscription
Get subscription
Application Lifecycle Management (ALM) APIs
Column formatting
Communication site
Shorter share links
SharePoint development overview
What's new for developers in SharePoint 2019
SharePoint glossary
Protocol handler error in SharePoint 2016
Programming models
SharePoint Add-ins compared with SharePoint solutions
Build farm solutions
Customize a field type using client-side rendering
URLs and tokens
Virtual directories in solutions
Access SharePoint from mobile and native device apps
Build Windows Phone apps that access SharePoint
Set up an environment for developing mobile apps
Application templates in Visual Studio
List Application template
Create a list app
Store and retrieve list items
Implement business logic and data validation
Support and convert field types
Customize list item queries and filter data
Customize the user interface of a list app
Use multiple lists
Configure and use push notifications
Create a mobile app that contains data from an external data source
Integrate maps with Windows Phone apps and lists
Build search-driven mobile apps with the Navigation and Event Logging REST
interfaces
SharePoint mobile object model
SharePoint mobile client authentication object model
Export the Name field in a Document Library list to a mobile app
Build localized applications based on SharePoint templates
Language support
Build mobile apps for other platforms
Build reusable components
Build sites for SharePoint
What's new with site development
Develop the site design
Design Manager
SharePoint page model
Master pages, the Master Page Gallery, and page layouts
Map a network drive to the Master Page Gallery
Apply a master page to a site
Create a page layout
Customize page layouts for a catalog-based site
Apply styles to page fields
Resolve errors and warnings when previewing a page
Convert an HTML file into a master page
Create a minimal master page
Change the preview page in Design Manager
SharePoint Online Suite Navigation control
Retrieve the URL of a Pages library
Branding and design capabilities
Design packages
Device channels
Display templates
Image renditions
Snippets
Themes
Managed metadata and navigation in SharePoint
Managed navigation
Content Search web part
Use code to pin terms to navigation term sets
Publish SharePoint sites
Cross-site publishing in SharePoint
User segmentation in SharePoint
Minimal Download Strategy overview
Modify SharePoint components for MDS
Optimize page performance
Optimize site accessibility
Add SharePoint capabilities
Workflows
Get started with workflows
Workflow fundamentals
What's new in workflows
Set up a workflow development environment
Configure MSMQ for workflows
Workflow initiation and configuration properties
Workflow development best practices
Debugging workflows
Using the pairing cmdlet Register-SPWorkflowService
Workflow samples
Develop SharePoint workflows using Visual Studio
Create a workflow app
Create workflows
SharePoint Workflow Services CSOM
Web Services in workflows
Tasks in workflows
Create custom SharePoint workflow forms
Build and deploy workflow custom actions
Use workflow interop for SharePoint
Common error messages in workflow development
SharePoint workflow object model
Develop workflows in SharePoint Designer and Visio
What's changed in SharePoint Designer
Create a workflow by using SharePoint Designer and the SharePoint Workflow
platform
Shapes in the SharePoint Server workflow template in Visio
Troubleshoot SharePoint Server workflow validation errors in Visio
Dictionary actions in SharePoint Designer
Coordination actions in SharePoint Designer
Task Actions in SharePoint Designer
Eventing Actions in SharePoint Designer
Visual Designer for workflow in SharePoint Designer
Web Services in SharePoint workflows using SharePoint Designer
Package and deploy workflow in SharePoint
Create a workflow with elevated permissions
Match the SharePoint Designer version with the farm version
Transfer a workflow between SharePoint Designer and Visio Professional
Workflow actions and activities reference
Workflow activity classes
Workflow actions quick reference
Workflow actions available using the workflow interop bridge
Workflow conditions quick reference (SharePoint 2010)
Workflow actions quick reference (SharePoint 2010)
Visio shapes in SharePoint Designer (SharePoint 2010)
Validation issues in Visio (SharePoint 2010)
Social and collaboration
What's new for developers
Get started developing with social features
Read and write to the social feed by using the .NET client object model
Read and write to the social feed by using the REST service
Social feed REST API reference
Following people and content REST API reference
Work with social feeds
Create and delete posts using the .NET client object model
Create and delete posts using the JavaScript object model
Include mentions, tags, and links to sites and documents
Embed images, videos, and documents
Reference threads and digest threads in feeds
Follow people
Follow people using the .NET client object model
Follow people using the JavaScript object model
Follow content
Follow documents and sites using the .NET client object model
Follow documents, sites, and tags using the REST service
Work with user profiles
Retrieve user profile properties using the .NET client object model
Retrieve user profile properties using the JavaScript object model
Work with user profiles using the server object model
Location and map functionality
Add a Geolocation column to a list programmatically
Create a map view for the Geolocation field
Set the Bing Maps key at the web and farm level
Extend the Geolocation field type by using client-side rendering
Search in SharePoint
What's new in SharePoint search for developers
Search new content
Search connector framework
Enhance the BDC model file for Search
Crawl associated external content types
Crawl binary large objects (BLOBs)
Configure item-level security
Configure search
Custom word breakers
Custom content processing with the Content Enrichment web service callout
Use the web service callout
Trigger expression syntax
Build search queries
Keyword Query Language (KQL) syntax reference
FAST Query Language (FQL) syntax reference
Using the SharePoint search Query APIs
Search REST API
Retrieve query suggestions using the Search REST service
Search add-ins
Customize search results
Sort search results
Customize ranking models
Custom security trimming
Use a custom security trimmer for search results
Export and import search configuration settings programmatically
Refine queries
Business Connectivity Services (BCS)
What's new in BCS
Get started with BCS
Set up a development environment for BCS
External content types
Create external content types for SQL Server
Create associations in SharePoint
Add-in-scoped external content types
Create an add-in-scoped external content type
Convert an add-in-scoped external content type to tenant-scoped
Access external data by using REST
Use OData sources with BCS
Create an external content type
Create an OData data service for use as a BCS external system
Create an external list
External events and alerts
Create external event receivers
Get started using the client object model with external data
Use the client code library to access external data
BCS programmers reference
BCS REST API reference
BCS client object model reference
Changes in the BDC model schema
BDC model schema reference
Create hybrid connectivity apps for SharePoint
Develop with Duet Enterprise 2.0
Use SAP workflow
Use SAP reporting
Office and SharePoint application services
Excel Services
Getting started
Overview
Architecture
Development roadmap
Features
Blogs, forums, and resources
Excel Web Services
What's new
Access the SOAP API
Loop-back SOAP calls and direct linking
Develop a custom application
Error codes
Get values from ranges
Set values of ranges
Specify a range address and sheet name
Get an entire workbook or a snapshot
Use the CloseWorkbook method call asynchronously
Set various credentials
Refresh data
Use the SubCode property to capture error codes
User-defined functions (UDFs)
Understand UDFs
Develop a managed-code UDF
FAQ about UDFs
Enable UDFs
Create a UDF that calls a web service
Access an external data source from a UDF
Deploy UDFs using SharePoint Foundation solutions
Restrict UDF code access security permissions
Excel Web Access
Programmatically add a web part to a page
Locate and copy required SharePoint DLLs
ECMAScript
Develop using the Content Editor web part
ECMAScript overview
JavaScript UDFs overview
JavaScript object model
Create a mashup that uses an embedded workbook and Bing Maps
Excel Services REST API
REST API overview
Basic URI structure and path
Discovery
Resources URI
Getting ranges using Atom feed and HTML fragment
Sample URI
Access a schema
Unsupported features
Advanced scenarios and additional samples
Use OData with REST in SharePoint
Request Excel workbook data from SharePoint Server using OData
General guidelines
Alerts
Known issues and tips
Best practices
Trust a location
Save from Excel client to the server
Save to the server to prepare for programmatic access
Catch exceptions
Remove Excel Interactive View from a webpage
Machine Translation Service
PerformancePoint Services
Create report renderers
Create report editors
Create filter data providers
Create filter editors
Create tabular data source providers
Create tabular data source editors
Create scorecard transforms
PowerPoint Automation Services
Access web apps
What's new in Access
Visio Services
Word Automation Services
Extend the fixed-format export feature
Authentication, authorization, and security
Authorization, users, groups, and the object model
Role, inheritance, elevation of privilege, and password changes
Claims-based identity
Sign in to SharePoint
Claims provider overview
Create a claims provider
Deploy a claims provider
Claims-based identity and concepts
Sample delegation, federation, and authentication scenario
Claims-based identity term definitions
Configuration, administration, and resources
eDiscovery
What's new in eDiscovery and compliance
CMIS
XLIFF interchange file format
Create no-code solutions
SharePoint Composites
Save a site as a template
Upgrade site customizations
Upgrade web templates
Use Feature upgrade to apply new master pages
Set up a development environment for SharePoint
How-tos for SharePoint
Code samples for SharePoint
Choose the right API set
Use the Office 365 content delivery network (CDN)
Use the site collection app catalog
Maintenance mode for client-side web parts
SharePoint Workflow Manager
SharePoint Application Lifecycle Management
Accessibility
Detect the installed SKU
Avoid getting throttled or blocked in SharePoint Online
Volume Shadow Copy Service (VSS)
VSS Writer
VSS requestors
Create a VSS requestor
Back up and restore SharePoint
Back up and restore a search service application
SharePoint Add-ins
Get started creating SharePoint-hosted add-ins
1. Deploy and install add-ins
2. Add custom columns
3. Add a custom content type
4. Add a web part to a page
5. Add a workflow
6. Add a custom page and style
7. Add custom client-side rendering
8. Create a custom ribbon button in the host web
9. Use the SharePoint JavaScript APIs to work with SharePoint data
10. Work with host web data from JavaScript in the add-in web
Get started creating provider-hosted add-ins
1. Give your add-in the SharePoint look-and-feel
2. Include a custom button
3. Get an overview of the SharePoint object model
4. Add write operations
5. Include an add-in part
6. Handle add-in events
7. Add first-run logic
8. Programmatically deploy a custom button
9. Handle list item events
Design
Design options for add-ins
Add-in architecture and development landscape
Patterns for developing and hosting an add-in
Host webs, add-in webs, and SharePoint components
Secure data access and client object models for add-ins
UX design for add-ins
SharePoint Add-ins UX design guidelines
Develop
Explore the app manifest structure and the package of an add-in
URL strings and tokens in add-ins
Create UX components in SharePoint
Use a SharePoint website's style sheet in add-ins
Use the client chrome control in add-ins
Create add-in parts to install with your add-in
Create custom actions to deploy with add-ins
Customize a list view in add-ins using client-side rendering
Use the client-side People Picker control in SharePoint-hosted add-ins
Highlight content and enhance the functionality of SharePoint-hosted add-ins with
the callout control
Include a web part in a webpage on the add-in web
Office Web Widgets - Experimental overview
Use the experimental People Picker widget in add-ins
Use the experimental Desktop List View widget in add-ins
Office Web Widgets - Experimental License Terms
Work with external data in SharePoint
Create a custom proxy page for the cross-domain library
Query a remote service using the web proxy
Handle events in add-ins
Create a remote event receiver
Create an add-in event receiver
Debug and troubleshoot a remote event receiver
Create a provider-hosted add-in that includes a custom SharePoint list and content
type
Get user identity and properties in SharePoint
Localize SharePoint Add-ins
Authorization and authentication of add-ins
Add-in permissions in SharePoint
Register add-ins
Add-in authorization policy types in SharePoint
Three authorization systems for add-ins
Creating add-ins that use low-trust authorization
Context Token OAuth flow for add-ins
Authorization Code OAuth flow for add-ins
Handle security tokens in provider-hosted low-trust add-ins
Use an Office 365 SharePoint site to authorize provider-hosted add-ins on an
on-premises SharePoint site
Replace an expiring client secret in an add-in
Creating add-ins that use high-trust authorization
Create high-trust add-ins
Create and use access tokens in provider-hosted high-trust add-ins
Troubleshooting high-trust add-ins
Package and publish high-trust add-ins
Creating add-ins that use the cross-domain library
Access SharePoint data from add-ins using the cross-domain library
Work with the cross-domain library across different Internet Explorer security
zones in SharePoint Add-ins
Create add-ins that can be used by anonymous users
Convert an autohosted add-in to a provider-hosted add-in
Create add-ins for the SAP Gateway for Microsoft
Create an add-in that contains a document template and a task pane add-in
Publish
Deploy and install add-ins
Tenancies and deployment scopes for add-ins
SharePoint Add-ins update process
Update add-ins
Update add-in web components in SharePoint
Update host web components in SharePoint
Update remote components in add-ins
Create a handler for the update event in add-ins
Publish add-ins by using Visual Studio
Tools
Set up a development environment for add-ins on Office 365
Create a developer site on an existing Office 365 subscription
Set up an on-premises development environment for add-ins
Create add-ins in Visual Studio
Solution guidance
Modernizing your classic SharePoint sites
Modernize the user interface
Maximize use of modern lists and libraries
Analyze and use the scanner data
Rollout approaches
Transform classic pages to modern client-side pages
Page transformation model
Page layout mapping
Page transformation API
Modernize customizations
Modernize site branding
Connect to an Office 365 group
Analyze and use the scanner data
Site permissions after Office 365 group connection
Branding and site provisioning solutions
Page model
Development and design tools and practices
Metadata, site navigation, and publishing site features
Site branding
Use composed looks to brand sites
Use remote provisioning to brand pages
Use CSS to brand pages
Customize elements of a page
Update the branding of existing sites and regions
Customize OneDrive for Business sites
Site provisioning
Implement a site classification solution
Modify host web lists at creation time
Create content types by using CSOM
Modify site permissions and get external sharing status
Manage users and groups
UX components
Customize the UX
Create UX controls
Improve performance
Customizing the "modern" experiences in SharePoint Online
Provision "modern" team sites programmatically
Customize "modern" team sites
Customize "modern" lists and libraries
Customize "modern" site pages
SharePoint "modern" sites classification
OneDrive and SharePoint Online Multi-Geo
Permissions model
Discover your tenant configuration
Access OneDrive for Business
Work with sites
Provision classic team sites
Manage apps/add-ins
Work with user profiles
Search in a tenant
Manage metadata
Define and publish content types
Connect to external data using BCS and Secure Store Service
Set up a sample application
Building SharePoint Online portals
Performance
Information architecture
Navigation
Content aggregation
Branding
Deployment
Composite business add-ins
Migrate InfoPath forms
Data storage options
Corporate event add-in integration
Call web services from workflows
ECM solutions
Document library templates
Auto-tagging
Information management
Records management extensions
Taxonomy operations
Bulk upload documents
Upload large files
Synchronize term groups
Support % and # in files and folders with ResourcePath API
Localization solutions
Use localization features
Localize UI elements
Search solutions
Search customizations
Security and performance
Authorization considerations for tenants hosted in Germany, China, or US
Handle SharePoint Online throttling
Set up app-only access to SharePoint
Grant access using Azure AD app-only
Grant access using SharePoint app-only
Implement a web app policy alternative
Migrate from permissive to strict tenant setting
Authorize provider-hosted add-in users at run time
Cross-domain images in provider-hosted add-ins
Elevated privileges in SharePoint Add-ins
Provide add-in app-only tenant administrative permissions in SharePoint Online
Develop using tenant permissions with app-only
Set external sharing in Office 365
JavaScript patterns and performance
SharePoint Add-in recipes
App-only and elevated privileges
Branding sites
Custom actions
Custom field type
Custom ribbons
Customize your site UI using JavaScript embedding
Delegate controls
Document ID provider
Event receivers and list event receivers
Feature stapling
Information management policy
JavaScript customizations
List definition/list template
List instance
Localization
Master pages
MMS manipulation
Modules
OneDrive for Business customization
Performance considerations
Remote timer jobs
Remote event receivers
Search API usage
Search configuration
SharePoint change log
Site columns and content types
Site provisioning
Asynchronous operations in SharePoint Add-ins
User controls and web controls
User profile manipulation
Variations
Web part
Upload web parts
Connect SharePoint Add-in parts
Workflows, actions (activities), events, and forms
Yammer integration
Transforming farm solutions
Replace content types and site columns
Replace files
Replace lists
Replace web parts
Transforming sandbox solutions
Replace web parts
Replace event receivers
Replace feature receivers
Fix code-based InfoPath forms
User profile solutions
Read or update user profile properties
Bulk update custom user profile properties
Migrate user profile properties
Personalize search results
Upload user profile pictures
Deploying your SharePoint Add-ins
Deploy sites to Azure
Use Azure WebJobs with Office 365
Configure provider-hosted add-ins for distribution
Configure Office 365 projects for distribution
PnP remote provisioning
PnP provisioning engine
PnP provisioning framework
PnP provisioning engine and the Core library
PnP provisioning schema
Provisioning console application sample
PnP remote timer job framework
PnP timer job framework
Create remote timer jobs
Get started with WebJobs
PnP Office 365 CLI
PnP PowerShell reference
PnP Sites Core API reference
PnP Sites Core API reference - Extension methods
SharePoint schema reference
SharePoint Add-in schemas
Schema reference for manifests of SharePoint Add-ins
Schema map (SharePoint Add-in Manifest)
Elements (SharePoint Add-in Manifest)
App element
AppPermissionRequest element
AppPermissionRequests element
AppPrerequisite element
AppPrerequisites element
AppPrincipal element
AutoDeployedWebApplication element
DebugInfo element
InstalledEventEndpoint element
Internal element
Properties element
Property element
RemoteEndpoint element
RemoteEndpoints element
RemoteWebApplication element
SettingsPage element
StartPage element
SupportedLanguages element
SupportedLocale element
SupportedLocales element
Title element
UninstallingEventEndpoint element
UpgradedEventEndpoint element
WebTemplate element
Types (SharePoint Add-in Manifest)
AppDefinition complexType
AppPermissionPropertyDefinition complexType
AppPermissionRequestDefinition complexType
AppPermissionRequestsDefinition complexType
AppPrerequisite complexType
AppPrerequisiteCollection complexType
AppPrincipalDefinition complexType
AutoDeployedWebApplicationDebugInfoDefinition complexType
PropertiesDefinition complexType
RemoteEndpointDefinition complexType
RemoteEndpointsDefinition complexType
SupportedLocaleDefinition complexType
SupportedLocalesDefinition complexType
UrlElementDefinition complexType
WebTemplateDefinition complexType
AppPermissionAppPrincipalDefinition simpleType
AppPermissionRightDefinition simpleType
AppPrerequisiteTypeDefinition simpleType
AppPrincipalTypeDefinition simpleType
AutoDeployedWebApplicationDebugInfoAppUrlDefinition simpleType
CultureNameDefinition simpleType
DescriptionDefinition simpleType
GUID simpleType
ManifestUri simpleType
NameDefinition simpleType
RestrictedInt simpleType
SupportedLanguagesDefinition simpleType
TitleDefinition simpleType
TypeDefinition simpleType
VersionDefinition simpleType
WebTemplateIdDefinition simpleType
AppHostWebFeatures schema reference
Schema map (AppHostWebFeatures)
Elements (AppHostWebFeatures)
ActivationDependencies element
ActivationDependency element
ApplyElementManifests element
Button element
CheckBox element
ClientWebPart element
ColorPicker element
ComboBox element
CommandUIDefinition element
CommandUIDefinitions element
CommandUIExtension element
CommandUIHandler element
CommandUIHandlers element
Content element
ContextualGroup element
ContextualTabs element
Controls element
CustomAction element (CustomActionDefinitions)
CustomAction element (ElementDefinitionCollection)
DropDown element
ElementFile element
ElementManifest element
ElementManifests element
Elements element
EnumItem element
EnumItems element
Feature element
Feature element (FeatureTemplateReferences)
FlyoutAnchor element
Gallery element
GalleryButton element
Group element
Groups element
GroupTemplate element
InsertTable element
Label element
MaxSize element
Menu element
MenuSection element
MRUSplitButton element
Properties element (FeatureDefinition)
Properties element (FeatureTemplateReference)
Properties element (ClientWebPartDefinition)
Property element (FeaturePropertyDefinitions)
Property element (PropertyBagDefinition)
Property element (ClientWebPartProperties)
QAT element
Ribbon element
Scale element
Scaling element
Spinner element
SplitButton element
Tab element
Tabs element
TextBox element
ToggleButton element
UpgradeActions element
UrlAction element
VersionRange element
Types (AppHostWebFeatures)
ClientWebPartDefinition complexType
ClientWebPartDefinitionContent complexType
ClientWebPartEnumItem complexType
ClientWebPartEnumItems complexType
ClientWebPartProperties complexType
ClientWebPartProperty complexType
CommandUIDefinitionsType complexType
CommandUIDefinitionType complexType
CommandUIExtensionType complexType
CommandUIHandlersType complexType
CommandUIHandlerType complexType
CustomActionDefinition complexType
CustomActionDefinitions complexType
ElementDefinitionCollection complexType
ElementManifestReference complexType
ElementManifestReferences complexType
FeatureActivationDependencyDefinition complexType
FeatureActivationDependencyDefinitions complexType
FeatureDefinition complexType
FeaturePropertyDefinition complexType
FeaturePropertyDefinitions complexType
FeatureTemplateReference complexType
FeatureTemplateReferences complexType
PropertyBagDefinition complexType
PropertyValueAttributeDefinition complexType
SimplePropertyDefinition complexType
UpgradeActionsDefinition complexType
UrlActionDefinition complexType
VersionRangeDefinition complexType
ClientWebPartDefinitionContentType simpleType
ClientWebPartPropertyType simpleType
CustomActionLocations simpleType
CustomActionRegistrationType simpleType
FeatureScope simpleType
FeatureVersion simpleType
PropertyBagParentTypeDefinition simpleType
PropertyBagType simpleType
UIVersion simpleType
WebPartPersonalizationScope simpleType
AppPartConfigDefinition schema reference
Schema map (AppPartConfigDefinition)
Elements (AppPartConfigDefinition)
AppPartConfig element
Id element
Types (AppPartConfigDefinition)
AppPartConfigDefinition complexType
GUID simpleType
Business connectivity services (BCS) schemas
SolutionManifestDefinitions schema
ContextDefinition element
ContextDefinitionGroup element
ContextDefinitionGroups element
Entities element
Entity element
OfficeItemCustomizations element
PromotedProperty element
SolutionDefinition element
SolutionSettings element
View element
OutlookItemCustomizations element
OfficeItemProperties element
OfficeItemProperty element
FormRegions element
FormRegion element
Picture element
OutlookFolder element
Associations element
Association element
Views element
FolderViewDefinition element
SolutionManifestDeclarativeExtensions schema
Actions element
CodeMethodAction element
ConstantParameter element
ContextActivated element
ContextDeactivated element
ContextEventHandlers element
DeclarativeAssociation element
DeclarativeContextDefinition element
DeclarativeContextDefinitionGroup element
DeclarativeFormRegion element
DeclarativeFormRegions element
DeclarativeSolutionSettings element
ExpressionParameter element
Layout element
Layouts element
Parameters element
Picture element
UrlAction element
LayoutDefinitions schema
ActionName element
ActionNames element
Children element
Container element
CustomProperties element
CustomProperty element
OBPart element
TitleBar element
Subscription schema
Association element
Associations element
FilterValue element
FilterValues element
FilterValues element
Identities element
Identity element
LocalizedDisplayName element
LocalizedDisplayNames element
Properties element
Property element
Queries element
Query element
Subscription element
BDCMetadata schema
AccessControlEntry element
AccessControlList element
Action element
ActionParameter element
ActionParameters element
Actions element
Association element
AssociationGroup element
AssociationGroups element
AssociationReference element
ConvertType element
DefaultValue element
DefaultValues element
DestinationEntity element
Entities element
Entity element
FilterDescriptor element
FilterDescriptors element
Identifier element
Identifiers element
Interpretation element
LobSystem element
LobSystemInstance element
LobSystemInstances element
LobSystems element
LocalizedDisplayName element
LocalizedDisplayNames element
Method element
MethodInstance element
MethodInstances element
Methods element
Model element
NormalizeDateTime element
Parameter element
Parameters element
Properties element
Property element
Proxy element
Right element
SourceEntity element
TypeDescriptor element
TypeDescriptors element
BDCMetadataResource schema
AccessControlEntry element
AccessControlList element
Action element
ActionParameter element
ActionParameters element
Actions element
Association element
AssociationGroup element
AssociationGroups element
Entities element
Entity element
FilterDescriptor element
FilterDescriptors element
Identifier element
Identifiers element
LobSystem element
LobSystemInstance element
LobSystemInstances element
LobSystems element
LocalizedDisplayName element
LocalizedDisplayNames element
Method element
MethodInstance element
MethodInstances element
Methods element
Model element
Parameter element
Parameters element
Properties element
Property element
Right element
TypeDescriptor element
TypeDescriptor element
TypeDescriptors element
Workflow schemas
WorkflowActions4 schema reference
Schema map (Workflow actions)
Elements (Workflow actions)
Action element
ActionBody element
ActionConditions element
Actions element
ActionVariables element
ActivityBody element
ActivitySource element
AssemblyRedirect element
AssemblyRedirects element
Block element
Blocks element
Coercion element
Coercions element
CompositeStep element
CompositeSteps element
Condition element
Conditions element
ContentType element
DataSource element
DataSourceRef element
DataSources element (Action element)
DataSources element (CompositeStep element)
Default element (Conditions element)
Default element (Actions element)
Dictionary element
Evaluation element
Event element
Events element
Field element
FieldBind element
Fields element
Flow element
Flows element
HashtableSource element
Modification element
Modifications element
NestedInitiationFieldNodes element
Option element
Parameter element (parametersType)
Parameter element (coercionParametersType)
Parameters element (Condition element)
Parameters element (Action element)
Parameters element (Coercion element)
Parameters element (Flow element)
Property element
RuleDesigner element (Default element)
RuleDesigner element (Condition element)
RuleDesigner element (Action element)
RuleDesigner element (Flow element)
RuleDesigner element (defaultElementType)
SchemaSource element
VariableType element
VariableTypes element
WorkflowInfo element
Types (Workflow actions)
appliesToTypes simpleType
coercionParametersType complexType
dataSourcesType complexType
dataSourceType complexType
defaultElementType complexType
parametersType complexType
propertiesType complexType
ruleDesignerType complexType
WorkflowActions3 schema reference
Action element
ActionBody element
ActionConditions element
ActionVariables element
ActivitySource element
ContentType element
DataSources element
DataSource element
DataSourceRef element
Default element
Dictionary element
Evaluation element
Field element
FieldBind element
Fields element
HashtableSource element
Modifications element
Modification element
NestedInitiationFieldNodes element
Option element
Parameter element
Parameters element
RuleDesigner element
SchemaSource element
WorkflowActions element
Workflow configuration schema reference
WorkflowConfig element
Template element
Association element
ContentTypes element
ContentType element
Initiation element
Fields element
Parameters element
Parameter element
WorkflowInfo schema reference
.ACTIONS File Example
Action element
ActionBody element
ActionConditions element
ActionVariables element
Actions element
Actions schema reference
ActivitySource element
AssemblyRedirect element
AssemblyRedirects element
Coercion element
Coercions element
Condition element
Conditions element
CompositeSteps element
CompositeStep element
ContentType element
DataSource element
DataSourceRef element
DataSources element
Default element
Default Workflow Actions
Default Workflow Conditions
Dictionary element
Evaluation element
Field element
FieldBind element
Fields element
HashtableSource element
Modification element
Modifications element
NestedInitiationFieldNodes element
Option element
Parameter element
Parameters element
RuleDesigner element
SchemaSource element
VariableType element
VariableTypes element
WorkflowInfo element
SharePoint Features schemas
Client Web Part Definition schema
Content Type Bindings
ContentTypeBinding element
Elements element
Content Type Definitions
ContentType element
DocumentTemplate element
Elements element
FieldRef element
FieldRefs element
Folder element
RemoveFieldRef element
XmlDocument element
XmlDocuments element
Custom Action Definition schema
CommandUIDefinitions element
CommandUIDefinition element
CommandUIExtension element
CommandUIHandlers element
CommandUIHandler element
CustomAction element
CustomActionGroup element
Elements element
HideCustomAction element
UrlAction element
Default Custom Action Locations and IDs
Delegate Controls
Control element
Elements element
Property element
Document Converter
DocumentConverter element
Elements element
Event Registrations
Assembly element
Class element
Data element
Elements element
Filter element
Name element
Receiver element
Receivers element
SequenceNumber element
SolutionId element
Synchronization element
Type element
SourceId element
SourceType element
Feature.xml Files
ActivationDependencies element
ActivationDependency element
AddContentTypeField element
ApplyElementManifests element
CustomUpgradeAction element
ElementFile element
ElementManifest element
ElementManifests element
Feature element
MapFile element
Parameter element
Parameters element
Properties element
Property element
UpgradeActions element
VersionRange element
Feature/Site Template Associations
Elements element
FeatureSiteTemplateAssociation element
Property element
Field Definitions
Elements element
Field element
List Instances
Data element
Elements element
Field element
ListInstance element
Row element
Rows element
DataSource element
Property element
List Template Files
Elements element
ListTemplate element
List Definition (Schema.xml) Files
Modules
AllUsersWebPart element
BinarySerializedWebPart element
Elements element
File element
GUID element
GUIDMap element
Module element
NavBarPage element
Property element
View element
WebPart element
WebPartConnection element
WebPartTransformer element
Property Bag schema
Elements element
PropertyBag element
Property element
Site Definition (Onet.xml) Files
Web Template XML
WebTemplate element
Elements
Workflow Definitions
AssociationCategories element
AssociationData element
Categories element
Elements element
ExtendedStatusColumnValues element
InitiationCategories element
InitiationType element
MetaData element
Modification_GUID_Name element
StatusColumnValue element
StatusPageUrl element
Workflow element (Elements)
Content migration schemas
DeploymentManifest schema
Selected Type Definitions
AnonymousState Simple Type
DefaultItemOpen Simple Type
DraftVisibilityType Simple Type
Guid Simple Type
ListItemDocType Simple Type
SecurityModificationType Simple Type
SPBaseType Simple Type
SPDictionaryEntryAccess Simple Type
SPDictionaryEntryValueType Simple Type
SPEventHostType Simple Type
SPEventReceiverType Simple Type
SPListTemplateType Simple Type
SPModerationStatusType Simple Type
SPObjectType Simple Type
SPViewScope Simple Type
TRUEFALSE Simple Type
Aggregations element (SPView)
Aggregations element (SPWebPart)
Assignment element
Attachment element
Attachments element
CalendarViewStyles element (SPView)
CalendarViewStyles element (SPWebPart)
ContentType element
ContentTypes element
DeletedField element
DeletedFields element
DocumentLibrary element
DocumentTemplate element
EventReceiver element
EventReceivers element (SPFile)
EventReceivers element (SPList)
EventReceivers element (SPListItem)
EventReceivers element (SPWeb)
Feature element
Field element (SPFieldCollection)
Field element (FieldDataCollection)
Field element (DeploymentFieldTemplate)
FieldRef element (SPFieldCollection)
FieldRef element (SPFieldLinkCollection)
Fields element (SPList)
Fields element (SPListItem)
FieldTemplate element
File element (SPGenericObject)
File element (SPFileVersionCollection)
Folder element
Form element
Formats element (SPView)
Formats element (SPWebPart)
Forms element
GroupByFooter element (SPView)
GroupByFooter element (SPWebPart)
GroupByHeader (SPView)
GroupByHeader (SPWebPart)
GroupX element
Link element
Links element (SPFile)
Links element (SPListItem)
List element
ListFormBody element (SPView)
ListFormBody element (SPWebPart)
ListItem element (SPGenericObject)
ListItem element (SPListItemVersionCollection)
ListTemplate element
Module element
PagedClientCallbackRowset element (SPView)
PagedClientCallbackRowset element (SPWebPart)
PagedRecurrenceRowset element (SPView)
PagedRecurrenceRowset element (SPWebPart)
PagedRowset element (SPView)
PagedRowset element (SPWebPart)
Personalization element
Personalizations element
PictureLibrary element
Properties element (SPAttachment)
Properties element (SPFile)
Properties element (SPFolder)
Properties element (SPModule)
Properties element (SPWeb)
Property element
Query element (SPView)
Query element (SPWebPart)
Role element
RoleAssignment element
RoleAssignments element
RoleAssignmentX element
Roles element
RoleX element
RowLimit element (SPView)
RowLimit element (SPWebPart)
RowLimitExceeded element (SPView)
RowLimitExceeded element (SPWebPart)
Script element (SPView)
Script element (SPWebPart)
Site element
SPObject element
SPObjects element
Toolbar element (SPView)
Toolbar element (SPWebPart)
UserX element
Versions element (SPFile)
Versions element (SPListItem)
View element
ViewBidiHeader element (SPView)
ViewBidiHeader element (SPWebPart)
View Body element (SPView)
View Body element (SPWebPart)
ViewData element (SPView)
ViewData element (SPWebPart)
ViewEmpty element (SPView)
ViewEmpty element (SPWebPart)
ViewFields element (SPView)
ViewFields element (SPWebPart)
ViewFooter element (SPView)
ViewFooter element (SPWebPart)
ViewHeader element (SPView)
ViewHeader element (SPWebPart)
Views element
ViewStyle element (SPView)
ViewStyle element (SPWebPart)
Web element
WebPart element
WebParts element
WebStructure element
WebTemplate element
DeploymentExportSettings schema
DeploymentObject element
ExportObjects element
ExportSettings element
Guid Simple Type
SPDeploymentObjectType Simple Type
SPExportMethodType Simple Type
SPIncludeDescendents Simple Type
SPIncludeSecurity Simple Type
SPIncludeVersions Simple Type
DeploymentLookupListMap schema
Guid Simple Type
LookupItem element
LookupItems element
LookupList element
LookupLists element
DeploymentRequirements schema
Requirement element
Requirements element
SPRequirementObjectType Simple Type
DeploymentRootObjectMap schema
Guid Simple Type
RootObject element
RootObjects element
SPDeploymentObjectType Simple Type
DeploymentSystemData schema
Guid Simple Type
ManifestFile element
ManifestFiles element
SchemaVersion element
SPDeploymentObjectType Simple Type
SystemData element
SystemObject element
SystemObjects element
DeploymentUserGroupMap schema
Group element
Groups element
Member element
User element
Users element
UserGroupMap element
DeploymentViewFormsList schema
ViewForm element
ViewFormsList element
Collaborative Application Markup Language (CAML) schemas
Introduction to Collaborative Application Markup Language (CAML)
Major CAML Files
Data-defining elements
HTML-rendering elements
Deprecated CAML elements
Query schema
And element
BeginsWith element
Contains element
DateRangesOverlap element
Eq element
FieldRef element
Geq element
GroupBy element
Gt element
In element
Includes element
IsNotNull element
IsNull element
Leq element
ListProperty element
Lt element
Membership element
Month element
Neq element
NotIncludes element
Now element
Or element
OrderBy element
Today element
UserID element
Value element
Values element
Where element
XML element
View schema
Global attributes for HTML-rendering elements
A- F
Batch element
Case element
Column element
Column2 element
ContentTypes element
Counter element
CurrentRights element
Default element
Else element
Expr element
Expr1 element
Expr2 element
Field element
FieldPrefix element
FieldProperty element
Fields element
FieldSortParams element
FieldSwitch element
FilterLink element
ForEach element
G- L
GetFileExtension element
GetVar element
HTML element
HttpHost element
HttpPath element
HttpVDir element
ID element
Identity element
IfEqual element
IfHasRights element
IfNeg element
IfNew element
IfSubString element
Join element
Joins element
Length element
Limit element
List element
ListProperty element
ListUrl element
ListUrlDir element
LookupColumn element
M-Z
MapToAll element
MapToContentType element
MapToControl element
MapToIcon element
MeetingProperty element
Method element
More element
PageUrl element
ProjectProperty element
ProjectedFields element
Property element
RightsChoices element
RightsGroup element
ScriptQuote element
SelectionOptions element
ServerProperty element
SetList element
SetVar element
Switch element
Text element
Then element
ThreadStamp element
URL element
UrlBaseName element
UrlDirName element
UserID element
WebQueryInfo element
List schema
A- K
Aggregations element
AllUsersWebPart element
ArrayOfProperty element
CHOICE element
CHOICES element
ContentTypeRef element
ContentTypes element
Customization element
Default element (Field)
Default element (Form)
DefaultDescription element
DefaultFormula element
DefaultFormulaValue element
DisplayBidiPattern element
DisplayPattern element
DocumentLibraryTemplate element
Field element
FieldRef element
FieldRefs element
Fields element
Filter element
Folder element
Form element
Forms element
Formula element
FormulaDisplayNames element
GroupByFooter element
GroupByHeader element
L- Z
List element
ListFormBody element
ListFormButtons element
ListFormClosing element
ListFormOpening element
MAPPING element
MAPPINGS element
MetaData element
Method element
PagedClientCallbackRowset element
PagedRecurrenceRowset element
PagedRowset element
ParameterBinding element
ParameterBindings element
Property element
Query element
RowLimit element
RowLimitExceeded element
Toolbar element
Validation element
View element
ViewBidiHeader element
ViewBody element
ViewData element
ViewEmpty element
ViewFields element
ViewFooter element
ViewHeader element
Views element
ViewStyle element
WebParts element
XslLink element
Site schema
A- L
AllUsersWebPart element
BaseType element
BaseTypes element
BinarySerializedWebPart element
Components element
Configuration element
Configurations element
Data element
DocumentTemplate element
DocumentTemplateFile element
DocumentTemplateFiles element
DocumentTemplates element
ExecuteUrl element
ExternalSecurityProvider element
Feature element
Field element
File element
FileDialogPostProcessor element
GUID element
GUIDMap element
List element
Lists element
ListTemplate element
ListTemplates element
M-Z
MetaData element
Module element
Modules element
NavBar element
NavBarLink element
NavBarPage element (Module)
NavBarPage element (NavBar)
NavBars element
Project element
Properties element
Property element (Feature)
Property element (Module)
Row element
Rows element
ServerEmailFooter element
SiteFeatures element
Template element
Templates element
View element
WebFeatures element
WebPart element
WebPartConnection element
WebPartTransformer element
Site Deletion Confirmation schema
AutoDeleteBody element
AutoDeleteSubject element
AutoDeleteWarning element
Confirmation element
ConfirmationBody element
ConfirmationSubject element
Email element
Regional Settings schema
Bias element
Currencies element
Currency element
Date element
Day element
DaylightTime element
DayOfWeek element
History element
Hour element
Language element
Languages element
Locale element
Locales element
Month element
RegionalSettings element
StandardTime element
TimeZone element
TimeZones element
Document Icons schema
ByExtension element
ByProgID element
DocIcons element
Mapping element
General schema
A- H
Attachments element
CategoryBot element
CrossProjectLink element
DataFormatLCID element
Discussions element
Escape element
FieldFilterImageURL element
FieldFilterOptions element
FieldSortImageURL element
Format element
FormatDef element
Formats element
GetProgID element
GlobalLists element
GUID element
HTMLBase element
HtmlTrInfo element
I -Z
IfOld element
ImagesPath element
InForm element
IsPrivilegedUser element
ListForm element
LocaleInfo element
Mapping element
MapToText element
OkToVote element
PresenceEnabled element
QuotedXML element
ReadSecurity element
Recurrence element
SchemaSecurity element
Script element
Security element
Site element
TodayISO element
UserEmail element
ViewStyles element
Week element
WriteSecurity element
SharePoint search settings portability schemas
SPS15XSDSearchSet1
Schema map (SPS15XSDSearchSet1)
Elements (SPS15XSDSearchSet1)
Active element
ArrayOfSource element
AuthInfo element
BuiltIn element
ConnectionTimeout element
ConnectionUrlTemplate element
CreatedDate element
Description element
HasPermissionToReadAuthInfo element
Id element
IndexOffset element
LastModifiedDate element
MaximumResponseLength element
Name element
Owner element
ProviderId element
QueryTransform element
Source element (ArrayOfSource)
Source element
Types (SPS15XSDSearchSet1)
ArrayOfSource complexType
Source complexType
SPS15XSDSearchSet2
Schema map (SPS15XSDSearchSet2)
Elements (SPS15XSDSearchSet2)
_AuthSchemeName element
_AuthSubmissionMethod element
_AuthSubmissionPath element
_Cookies element
_ErrorPageUrl element (CookieAuthData)
_ErrorPageUrl element (FormsAuthCredentials)
_nameValuePairs element
_NameValuePairs element
_SecurableNameValuePairs element
_SsoAppId element
_UserName element
AccountAuthCredentials element
Aliases element
AliasesOverridden element
AliasInfo element
AliasInfoCollection element
Anchoring element
ArrayOfCrawledPropertyInfo element
ArrayOfManagedPropertyInfo element
ArrayOfPropertyRule element
ArrayOfResultItemType element
AuthenticationData element
AuthenticationInformation element
AuthenticationType element
BaseInfo element
BaseInfoCollectionOfAliasInfoTzWWwPjw element
BaseInfoCollectionOfCrawledPropertyInfoTzWWwPjw element
BaseInfoCollectionOfManagedPropertyInfoTzWWwPjw element
BaseInfoCollectionOfMappingInfoTzWWwPjw element
BaseInfoCollectionOfOverrideInfoTzWWwPjw element
BuiltIn element
CategoryName element
CompleteMatching element
Context element
CookieAuthData element
CrawledPropertyInfo element
CrawledPropertyInfo element (ArrayOfCrawledPropertyInfo)
CrawledPropertyInfoCollection element
CrawledPropertyName element
CrawledPropset element
CutoffMaxBuckets element
Data element
DatabaseId element
DeleteDisallowed element
Description element
DescriptionLSID element
Dictionary element (AliasInfo)
Dictionary element (CrawledPropertyInfo)
Dictionary element (ManagedPropertyInfo)
Dictionary element (MappingInfo)
Dictionary element (OverrideInfo)
DisableInheritance element
DisplayProperties element
DisplayTemplateUrl element
Divisor element
EnabledForScoping element
EntityExtractorBitMap element
ExtraProperties element
FederationAuthType element
FormsAuthCredentials element
FullTextIndex element
HasMultipleValues element
ID element
IndexOptions element
InternalID element
Intervals element
IsDeleted element
IsFunction element
IsMappedToContents element
IsNameEnum element
IsQuoted element
IsReadOnly element
JoinedByOr element
LastItemName element (AliasInfo)
LastItemName element (CrawledProperty)
LastItemName element (ManagedPropertyInfo)
LastItemName element (MappingInfo)
LastItemName element (OverrideInfo)
LastModifiedDate element
ManagedDataType element
ManagedPid element (AliasInfo)
ManagedPid element (MappingInfo)
ManagedPid element (OverrideInfo)
ManagedPropertyInfo element (ArrayOfManagedPropertyInfo)
ManagedPropertyInfo element
ManagedPropertyInfoCollection element
ManagedType element
MappedCrawledProperties element
MappedManagedProperties element
MappingDisallowed element
MappingInfo element
MappingInfoCollection element
MappingOrder element
MappingsOverridden element
Name element (ResultItemType)
Name element (PropertyRuleOperator)
Name element (BaseInfo)
NameLSID element
OptimizeForFrequentUse element
OverrideInfo element
OverrideInfoCollection element
Owner element
Password element
Pid element
PropertyName element
PropertyOperator element
PropertyRule element (ArrayOfPropertyRule)
PropertyRule element
PropertyRuleCollection element
PropertyRuleOperator element
PropertyRules element
PropertyValues element
Propset element
Queryable element
Refinable element
RefinerAnchoring element
RefinerConfiguration element (ManagedPropertyInfo)
RefinerConfiguration element
RefinerType element
RemoveDuplicates element
Representation element
Resolution element
RespectPriority element
ResultItemType element (ArrayOfResultItemType)
ResultItemType element
Retrievable element
RuleNameLSID element
RulePriority element
Rules element
SafeForAnonymous element
Samples element
SchemaID element (AliasInfo)
SchemaID element (CrawledPropertyInfo)
SchemaID element (MappingInfo)
SchemaID element (OverrideInfo)
Searchable element
SearchObjectOwner element
SecurableAuthData element
SerializableSecurableNameValuePairs element
Sortable element
SortableType element (ManagedPropertyInfo)
SortableType element
SourceID element
SPFarmId element
SPSiteId element
SPSiteSubscriptionId element
SPWebId element
SsoAuthData element
TokenNormalization element (ManagedPropertyInfo)
TokenNormalization element (OverrideInfo)
TotalCount element
Type element
UpdateGroup element
Types (SPS15XSDSearchSet2)
AccountAuthCredentials complexType
AliasInfo complexType
AliasInfoCollection complexType
ArrayOfCrawledPropertyInfo complexType
ArrayOfManagedPropertyInfo complexType
ArrayOfPropertyRule complexType
ArrayOfResultItemType complexType
AuthenticationData complexType
AuthenticationInformation complexType
BaseInfo complexType
BaseInfoCollectionOfAliasInfoTzWWwPjw complexType
BaseInfoCollectionOfCrawledPropertyInfoTzWWwPjw complexType
BaseInfoCollectionOfManagedPropertyInfoTzWWwPjw complexType
BaseInfoCollectionOfMappingInfoTzWWwPjw complexType
BaseInfoCollectionOfOverrideInfoTzWWwPjw complexType
CookieAuthData complexType
CrawledPropertyInfo complexType
CrawledPropertyInfoCollection complexType
FormsAuthCredentials complexType
ManagedPropertyInfo complexType
ManagedPropertyInfoCollection complexType
MappingInfo complexType
MappingInfoCollection complexType
OverrideInfo complexType
OverrideInfoCollection complexType
PropertyRule complexType
PropertyRuleCollection complexType
PropertyRuleOperator complexType
RefinerConfiguration complexType
ResultItemType complexType
SearchObjectOwner complexType
SecurableAuthData complexType
SsoAuthData complexType
FederationAuthType simpleType
ManagedDataType simpleType
RefinerAnchoring simpleType
RefinerType simpleType
SortableType simpleType
SPS15XSDSearchSet3
Schema map (SPS15XSDSearchSet3)
Elements (SPS15XSDSearchSet3)
Aliases element
ArrayOfSearchQueryConfigurationSettings element
BestBets element
CategoriesAndCrawledProperties element
CrawledProperties element
DefaultSourceId element
DefaultSourceIdSet element
DeployToParent element
DisableInheritanceOnImport element
ManagedProperties element
Mappings element
Overrides element
QueryRuleGroups element
QueryRules element
RankingModels element
ResultTypes element
SearchConfigurationSettings element
SearchQueryConfigurationSettings element (SearchConfigurationSettings)
SearchQueryConfigurationSettings element
(ArrayOfSearchQueryConfigurationSettings)
SearchQueryConfigurationSettings element
SearchRankingModelConfigurationSettings element
(SearchConfigurationSettings)
SearchRankingModelConfigurationSettings element
SearchSchemaConfigurationSettings element (SearchConfigurationSettings)
SearchSchemaConfigurationSettings element
Sources element
UserSegments element
Types (SPS15XSDSearchSet3)
ArrayOfSearchQueryConfigurationSettings complexType
SearchConfigurationSettings complexType
SearchQueryConfigurationSettings complexType
SearchRankingModelConfigurationSettings complexType
SearchSchemaConfigurationSettings complexType
SPS15XSDSearchSet4
Schema map (SPS15XSDSearchSet4)
Elements (SPS15XSDSearchSet4)
BoundVariableOrigin element
GroupProcessingDirective element
LicenseType element
MatchingOptions element
QueryActionEnableOnClickThroughOptions element
QueryTransformParentType element
Types (SPS15XSDSearchSet4)
BoundVariableOrigin simpleType
GroupProcessingDirective simpleType
LicenseType simpleType
MatchingOptions simpleType
QueryActionEnableOnClickThroughOptions simpleType
QueryTransformParentType simpleType
SPS15XSDSearchSet5
Schema map (SPS15XSDSearchSet5)
Elements (SPS15XSDSearchSet5)
AlertChangeType element
ArrayOfReorderingRule element
Boost element
KeywordInclusion element
MatchType element
MatchValue element
QueryAuthenticationType element
QueryHint element
ReorderingRule element (ArrayOfReorderingRule)
ReorderingRule element
ReorderingRuleMatchType element
ResubmitFlag element
ResultType element
SearchProvider element
SimilarType element
SortDirection element
SpellcheckMode element
Types (SPS15XSDSearchSet5)
AlertChangeType simpleType
KeywordInclusion simpleType
QueryAuthenticationType simpleType
QueryHint simpleType
ReorderingRuleMatchType simpleType
ResubmitFlag simpleType
ResultType simpleType
SearchProvider simpleType
SimilarType simpleType
SortDirection simpleType
SpellcheckMode simpleType
ArrayOfReorderingRule complexType
ReorderingRule complexType
SPS15XSDSearchSet6
Schema map (SPS15XSDSearchSet6)
Elements (SPS15XSDSearchSet6)
LocStringId element
Types (SPS15XSDSearchSet6)
LocStringId simpleType
Other SharePoint schemas
Field Types schema
FieldTypes element
FieldType element
Field element
PropertySchema element
Fields element
Field element
Default element
RenderPattern element
AlertTemplates schema
AlertTemplate element
AlertTemplates element
Digest element
DigestNotificationExcludedFields element
EventTypes element
Fields element
FilterDefinition element
Filters element
Footer element
Format element
FriendlyName element
Header element
HeaderFields element
HeaderFieldsFooter element
HeaderFieldsHeader element
Immediate element
ImmediateNotificationExcludedFields element
NotificationHandlerAssembly element
NotificationHandlerClassName element
Properties element
Query element
RowFields element
RowFooter element
RowHeader element
ShortName element
Subject element
UpdateHandlerAssembly element
UpdateHandlerClassName element
Mobile Document Viewer schema
MobileDocViewers element
MobileDocViewer element
BrowserCondition element
Override element
Server Ribbon schema
Button element
CheckBox element
ColorPicker element
Colors element
Color element
ComboBox element
CommandUI element
ContextualGroup element
ContextualTabs element
ControlRef element
Controls element (CommandUIDefinition)
Controls element (Group)
Controls element (MenuSection)
DropDown element
FlyoutAnchor element
Gallery element
GalleryButton element (Gallery)
GalleryButton element (Group)
Groups element
Group element
GroupTemplate element
InsertTable element
Jewel element
Label element
Layout element
MaxSize element
Menu element
MenuSection element
MRUSplitButton element
OverflowSection element
OverflowArea element
QAT element
Ribbon element
RibbonTemplates element
Row element
Scale element
Scaling element
Section element
Spinner element
SplitButton element
Strip element
Tabs element
Tab element
Templates element
TextBox element
ToggleButton element
Unit element
UnitAbbreviation element
Solution schema
ActivationDependencies element
ActivationDependency element
App_GlobalResourceFile element
ApplicationResourceFile element
ApplicationResourceFiles element
Assemblies element (Assemblies)
Assemblies element (CodeAccessSecurity)
Assembly element (Assemblies)
Assembly element (CodeAccessSecurity)
BindingRedirect element
BindingRedirects element
ClassResource element
ClassResources element
CodeAccessSecurity element
DwpFile element
DwpFiles element
FeatureManifest element
FeatureManifests element
IPermission element
PermissionSet element
PolicyItem element
Resource element
Resources element
RootFile element
RootFiles element
SafeControl element
SafeControls element
SiteDefinitionManifest element
SiteDefinitionManifests element
Solution element
TemplateFile element
TemplateFiles element
WebTempFile element
SPMetal Parameters schema
Column element
ContentType element
ExcludeColumn element
ExcludeContentType element
ExcludeList element
ExcludeOtherColumns element
ExcludeOtherContentTypes element
ExcludeOtherLists element
IncludeHiddenColumns element
IncludeHiddenContentTypes element
IncludeHiddenLists element
List element
Web element
Upgrade Definition schema
AppliedSiteFeatures element
AppliedWebFeatures element
Config element
Feature element
File element
Files element
List element
Lists element
WebTemplate element
dsQueryResponse schema
dsQueryResponse element
Rows element
Row element
Community
Contribute
Contribute
Open source projects
GitHub repositories
Submit issues
Submit feature requests
SharePoint developer videos on YouTube
Office development on Twitter
SharePoint developer forum
Tutorials
Build SharePoint Framework solutions, apps, add-ins, and solutions for SharePoint for your enterprise or customer needs.
Setup
Get started
Community
Videos
Samples
Ideas
Issues
Forum
SharePoint Framework
Overview of the SharePoint Framework
Set up your development environment
Build your first client-side web part
SharePoint webhooks
Overview of SharePoint webhooks
Get started with SharePoint webhooks
SharePoint list webhooks
SharePoint Add-ins
Overview of SharePoint Add-ins
Provider-hosted add-ins
SharePoint-hosted add-ins
Solution guidance
Modernize your classic SharePoint sites
Customizing modern experiences
Building SharePoint Online portals
"Sharing is caring!"
Overview of the SharePoint Framework
4/20/2018 • 5 minutes to read Edit Online
The SharePoint Framework (SPFx) is a page and web part model that provides full support for client-side SharePoint development, easy integration with SharePoint data, and support for
open source tooling. With the SharePoint Framework, you can use modern web technologies and tools in your preferred development environment to build productive experiences and apps
that are responsive and mobile-ready from day one. The SharePoint Framework works for SharePoint Online and soon also for on-premises (SharePoint 2016 Feature Pack 2).
Key features of the SharePoint Framework include the following:
It runs in the context of the current user and connection in the browser. There are no iFrames for the customization (JavaScript is embedded directly to the page).
The controls are rendered in the normal page DOM.
The controls are responsive and accessible by nature.
It enables the developer to access the lifecycle in addition to render, load, serialize and deserialize, configuration changes, and more.
It is framework-agnostic. You can use any JavaScript framework that you like: React, Handlebars, Knockout, Angular, and more.
The toolchain is based on common open source client development tools such as npm, TypeScript, Yeoman, webpack, and gulp.
Performance is reliable.
End users can use SPFx client-side solutions that are approved by the tenant administrators (or their delegates) on all sites, including self-service team, group, or personal sites.
SPFx web parts can be added to both classic and modern pages.
The runtime model improves on the Script Editor web part. It includes a robust client API, an HttpClient object that handles authentication to SharePoint and Office 365, contextual
information, easy property definition and configuration, and more.
If you work primarily with C#, you want to learn more about client-side JavaScript development. Most of your existing JavaScript knowledge related to SharePoint, however, is completely
transferable, as the data models have not changed, and you’ll use the same REST services or JavaScript Object Model (JSOM), depending on your requirements. If you are a C# developer,
TypeScript is a nice transition into the JavaScript world. The choice of IDE is up to you. Many developers like to use the cross-platform IDE Visual Studio Code. Many developers also use
products like Sublime and ATOM. Use what works best for you.
JavaScript injection
One of the most popular web parts in SharePoint Online is the Script Editor. You can paste JavaScript into the Script Editor web part and have that JavaScript execute when the page renders.
It’s simple and rudimentary, but effective. It runs in the same browser context as the page, and is in the same DOM, so it can interact with other controls on the page. It is also relatively
performant, and simple to use.
There are a few downsides to this approach, however. First, while you can package your solution so that end users can drop the control onto the page, you can't easily provide configuration
options. Also, the end user can edit the page and modify the script, which can break the web part. Another big problem is that the Script Editor web part is not marked as "Safe For
Scripting". Most self-service site collections (my-sites, team sites, group sites) have a feature known as "NoScript" enabled. Technically, it is the removal of the Add/Customize Pages (ACP)
permission in SharePoint. This means that the Script Editor web part will be blocked from executing on these sites.
SharePoint Framework
Historically, we created web parts as full trust C# assemblies that were installed on the cloud servers. However, current development models for the most part involve JavaScript running in a
browser making REST API calls to the SharePoint and Office 365 back-end workloads. C# assemblies don’t work in this world. We needed a new development model. The SharePoint
Framework is the next evolution in SharePoint development.
What's next?
SharePoint Framework web parts and extensions have now reached General Availability (GA). We continue to provide updates and refinements over time based on your feedback and
experiences. For any additional SharePoint Framework capabilities that are first launched in preview mode, you might experience occasional breaking changes around API names, flows, and
more. Future updates to the SharePoint Framework will be backward-compatible so that your solutions continue to work.
Questions?
If you have any questions, post them on SharePoint StackExchange. Tag your questions and comments with #spfx, #spfx-webparts, and #spfx-tooling.
You can also post issues, questions, or feedback about the docs or the SharePoint Framework in our GitHub repo.
See also
Overview of SharePoint client-side web parts
Overview of SharePoint Framework Extensions
SharePoint development
SharePoint glossary
Set up your Office 365 tenant
3/26/2018 • 2 minutes to read Edit Online
To build and deploy client-side web parts using the SharePoint Framework, you need an Office 365 tenant.
If you already have an Office 365 tenant, see the section Create app catalog site.
If you don't have one, you can get an Office 365 developer subscription when you join the Office 365 Developer Program. See the Office 365 Developer Program documentation for step-
by-step instructions about how to join the Office 365 Developer Program and sign up and configure your subscription.
NOTE
Make sure that you are signed out of any existing Office 365 tenants before you sign up.
https://yourtenantprefix-admin.sharepoint.com
2. In the left sidebar, select the apps menu item, and then select app catalog.
3. Select OK to create a new app catalog site.
4. On the next page, enter the following details:
Title: Enter app catalog.
Web Site Address suffix: Enter your preferred suffix for the app catalog; for example: apps.
Administrator: Enter your username, and then select the resolve button to resolve the username.
5. Select OK to create the app catalog site.
SharePoint creates the app catalog site, and you are able to see its progress in the SharePoint admin center.
https://yourtenantprefix-admin.sharepoint.com
SharePoint Workbench
SharePoint Workbench is a developer design surface that enables you to quickly preview and test web parts without deploying them in SharePoint. SharePoint Framework developer
toolchain contains a version of the Workbench that works locally and helps you quickly test and validate solutions that you are building. It is also hosted in your tenancy to preview and test
your local web parts in development. You can access the SharePoint Workbench from any SharePoint site in your tenancy by browsing to the following URL:
https://your-sharepoint-site/_layouts/workbench.aspx
Next steps
Now that you have configured your SharePoint tenant, set up your development environment to build client-side web parts.
Set up your Office 365 tenant
3/26/2018 • 2 minutes to read Edit Online
To build and deploy client-side web parts using the SharePoint Framework, you need an Office 365 tenant.
If you already have an Office 365 tenant, see the section Create app catalog site.
If you don't have one, you can get an Office 365 developer subscription when you join the Office 365 Developer Program. See the Office 365 Developer Program documentation for step-
by-step instructions about how to join the Office 365 Developer Program and sign up and configure your subscription.
NOTE
Make sure that you are signed out of any existing Office 365 tenants before you sign up.
https://yourtenantprefix-admin.sharepoint.com
2. In the left sidebar, select the apps menu item, and then select app catalog.
3. Select OK to create a new app catalog site.
4. On the next page, enter the following details:
Title: Enter app catalog.
Web Site Address suffix: Enter your preferred suffix for the app catalog; for example: apps.
Administrator: Enter your username, and then select the resolve button to resolve the username.
5. Select OK to create the app catalog site.
SharePoint creates the app catalog site, and you are able to see its progress in the SharePoint admin center.
https://yourtenantprefix-admin.sharepoint.com
SharePoint Workbench
SharePoint Workbench is a developer design surface that enables you to quickly preview and test web parts without deploying them in SharePoint. SharePoint Framework developer
toolchain contains a version of the Workbench that works locally and helps you quickly test and validate solutions that you are building. It is also hosted in your tenancy to preview and test
your local web parts in development. You can access the SharePoint Workbench from any SharePoint site in your tenancy by browsing to the following URL:
https://your-sharepoint-site/_layouts/workbench.aspx
Next steps
Now that you have configured your SharePoint tenant, set up your development environment to build client-side web parts.
Set up your SharePoint Framework development environment
6/18/2018 • 2 minutes to read Edit Online
You can use Visual Studio or your own custom development environment to build SharePoint Framework solutions. You can use a Mac, PC, or Linux.
NOTE
Before following the steps in this article, be sure to Set up your Office 365 tenant.
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/-tXf8gxjmOI
Current LTS version of NodeJS is 8.11.3. Notice that 9.x versions are currently not supported with SharePoint Framework development.
If you need to switch between the different projects created by using different versions of the SharePoint Framework Yeoman generator, you can install the generator locally as a
development dependency in the project folder by executing the following command:
For more information about the Yeoman SharePoint generator, see Scaffold projects by using Yeoman SharePoint generator.
Optional tools
Following are some tools that might come in handy as well:
Fiddler
Postman plug-in for Chrome
Cmder for Windows
Oh My Zsh for Mac
Git source control tools
Next steps
You are now ready to build your first client-side web part!
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at sp-dev-docs repository. Thanks for your input in
advance.
Overview of SharePoint client-side web parts
3/26/2018 • 2 minutes to read Edit Online
SharePoint client-side web parts are controls that appear inside a SharePoint page but run locally in the browser. They're the building blocks of pages that appear on a SharePoint site.
You can build client-side web parts using modern script development tools and the SharePoint workbench (a development test surface), and you can deploy your client-side web parts to
modern pages and classic web part pages in Office 365 tenants.
In addition to plain JavaScript projects, you can build web parts alongside common scripting frameworks, such as AngularJS and React. For example, you can use React along with
components from Office UI Fabric React to quickly create experiences based on the same components used in Office 365.
For more information, see the Getting started, Basics, and Concepts sections (in the TOC).
See also
Overview of the SharePoint Framework
SharePoint Framework development tools and libraries
Build your first SharePoint client-side web part (Hello World part 1)
6/18/2018 • 11 minutes to read Edit Online
Client-side web parts are client-side components that run inside the context of a SharePoint page. Client-side web parts can be deployed to SharePoint Online, and you can also use modern
JavaScript tools and libraries to build them.
Client-side web parts support:
Building with HTML and JavaScript.
Both SharePoint Online and on-premises environments.
NOTE
Before following the steps in this article, be sure to Set up your development environment.
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/YqUIX2pMUzg
md helloworld-webpart
cd helloworld-webpart
3. Create a new HelloWorld web part by running the Yeoman SharePoint Generator.
yo @microsoft/sharepoint
4. When prompted:
Accept the default helloworld-webpart as your solution name, and then select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Accept the default HelloWorld as your web part name, and then select Enter.
Accept the default HelloWorld description as your web part description, and then select Enter.
Accept the default No javascript web framework as the framework you would like to use, and then select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld web part. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold.
gulp trust-dev-cert
2. Now that we have installed the developer certificate, enter the following command in the console to build and preview your web part:
gulp serve
This command executes a series of gulp tasks to create a local, node-based HTTPS server on localhost:4321 and launches your default browser to preview web parts from your local dev
environment.
SharePoint client-side development tools use gulp as the task runner to handle build process tasks such as:
Bundling and minifying JavaScript and CSS files.
Running tools to call the bundling and minification tasks before each build.
Compiling SASS files to CSS.
Compiling TypeScript files to JavaScript.
Visual Studio Code provides built-in support for gulp and other task runners. Select Ctrl+Shift+B on Windows or Cmd+Shift+B on Mac to debug and preview your web part.
SharePoint Workbench is a developer design surface that enables you to quickly preview and test web parts without deploying them in SharePoint. SharePoint Workbench includes the
client-side page and the client-side canvas in which you can add, delete, and test your web parts in development.
The property pane is where you can define properties to customize your web part. The property pane is client-side driven and provides a consistent design across SharePoint.
4. Modify the text in the Description text box to Client-side web parts are awesome!
Notice how the text in the web part also changes as you type.
One of the new capabilities available to the property pane is to configure its update behavior, which can be set to reactive or non-reactive. By default, the update behavior is reactive and
enables you to see the changes as you edit the properties. The changes are saved instantly when the behavior is reactive.
code .
If you get an error, you might need to install the code command in PATH.
TypeScript is the primary language for building SharePoint client-side web parts. TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. SharePoint client-side
development tools are built using TypeScript classes, modules, and interfaces to help developers build robust client-side web parts.
The following are some key files in the project.
This property definition is used to define custom property types for your web part, which is described in the property pane section later.
Web part render method
The DOM element where the web part should be rendered is available in the render method. This method is used to render the web part inside that DOM element. In the HelloWorld web
part, the DOM element is set to a DIV. The method parameters include the display mode (either Read or Edit) and the configured web part properties if any:
This model is flexible enough so that web parts can be built in any JavaScript framework and loaded into the DOM element.
Configure the Web part property pane
The property pane is defined in the HelloWorldWebPart class. The propertyPaneSettings property is where you need to define the property pane.
When the properties are defined, you can access them in your web part by using this.properties.<property-value> , as shown in the render method:
<p class="${styles.description}">${escape(this.properties.description)}</p>
Notice that we are performing an HTML escape on the property's value to ensure a valid string. To learn more about how to work with the property pane and property pane field types, see
Make your SharePoint client-side web part configurable.
Let's now add a few more properties to the property pane: a check box, a drop-down list, and a toggle. We first start by importing the respective property pane fields from the framework.
1. Scroll to the top of the file and add the following to the import section from @microsoft/sp-webpart-base :
PropertyPaneCheckbox,
PropertyPaneDropdown,
PropertyPaneToggle
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
PropertyPaneCheckbox,
PropertyPaneDropdown,
PropertyPaneToggle
} from '@microsoft/sp-webpart-base';
2. Update the web part properties to include the new properties. This maps the fields to typed objects.
3. Replace the IHelloWorldWebPartProps interface with the following code.
6. After you add your properties to the web part properties, you can now access the properties in the same way you accessed the description property earlier:
To set the default value for the properties, you need to update the web part manifest's properties property bag.
7. Open HelloWorldWebPart.manifest.json and modify the properties to:
"properties": {
"description": "HelloWorld",
"test": "Multi-line text field",
"test1": true,
"test2": "2",
"test3": true
}
The web part property pane now has these default values for those properties.
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "7d5437ee-afc2-4e66-914b-80be5ace4056",
"alias": "HelloWorldWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "HelloWorld" },
"description": { "default": "HelloWorld description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "HelloWorld",
"test": "Multi-line text field",
"test1": true,
"test2": "2",
"test3": true
}
}]
}
Now that we have introduced new properties, ensure that you are again hosting the web part from the local development environment by executing the following command. This also
ensures that the previous changes were correctly applied.
gulp serve
NOTE
If you do not have the SPFx developer certificate installed, Workbench notifies you that it is configured not to load scripts from localhost. Stop the currently running process in the
console window, and execute the gulp trust-dev-cert command in your project directory console to install the developer certificate before running the gulp serve command again.
2. Notice that the SharePoint Workbench now has the Office 365 Suite navigation bar.
3. Select the add icon in the canvas to reveal the toolbox. The toolbox now shows the web parts available on the site where the SharePoint Workbench is hosted along with your
HelloWorldWebPart.
4. Add HelloWorld from the toolbox. Now you're running your web part in a page hosted in SharePoint!
NOTE
The color of the web part depends on the colors of the site. By default, web parts inherit the core colors from the site by dynamically referencing Office UI Fabric Core styles used in the site
where the web part is hosted.
Because you are still developing and testing your web part, there is no need to package and deploy your web part to SharePoint.
Next steps
Congratulations on getting your first Hello World web part running!
Now that your web part is running, you can continue building out your Hello World web part in the next topic, Connect your web part to SharePoint. You will use the same Hello World web
part project and add the ability to interact with SharePoint List REST APIs. Notice that the gulp serve command is still running in your console window (or in Visual Studio Code if you are
using that as editor). You can continue to let it run while you go to the next article.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, please report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your
input in advance.
Build your first SharePoint client-side web part (Hello World part 1)
6/18/2018 • 11 minutes to read Edit Online
Client-side web parts are client-side components that run inside the context of a SharePoint page. Client-side web parts can be deployed to SharePoint Online, and you can also use modern
JavaScript tools and libraries to build them.
Client-side web parts support:
Building with HTML and JavaScript.
Both SharePoint Online and on-premises environments.
NOTE
Before following the steps in this article, be sure to Set up your development environment.
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/YqUIX2pMUzg
md helloworld-webpart
cd helloworld-webpart
3. Create a new HelloWorld web part by running the Yeoman SharePoint Generator.
yo @microsoft/sharepoint
4. When prompted:
Accept the default helloworld-webpart as your solution name, and then select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Accept the default HelloWorld as your web part name, and then select Enter.
Accept the default HelloWorld description as your web part description, and then select Enter.
Accept the default No javascript web framework as the framework you would like to use, and then select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld web part. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold.
gulp trust-dev-cert
2. Now that we have installed the developer certificate, enter the following command in the console to build and preview your web part:
gulp serve
This command executes a series of gulp tasks to create a local, node-based HTTPS server on localhost:4321 and launches your default browser to preview web parts from your local dev
environment.
SharePoint client-side development tools use gulp as the task runner to handle build process tasks such as:
Bundling and minifying JavaScript and CSS files.
Running tools to call the bundling and minification tasks before each build.
Compiling SASS files to CSS.
Compiling TypeScript files to JavaScript.
Visual Studio Code provides built-in support for gulp and other task runners. Select Ctrl+Shift+B on Windows or Cmd+Shift+B on Mac to debug and preview your web part.
SharePoint Workbench is a developer design surface that enables you to quickly preview and test web parts without deploying them in SharePoint. SharePoint Workbench includes the
client-side page and the client-side canvas in which you can add, delete, and test your web parts in development.
The property pane is where you can define properties to customize your web part. The property pane is client-side driven and provides a consistent design across SharePoint.
4. Modify the text in the Description text box to Client-side web parts are awesome!
Notice how the text in the web part also changes as you type.
One of the new capabilities available to the property pane is to configure its update behavior, which can be set to reactive or non-reactive. By default, the update behavior is reactive and
enables you to see the changes as you edit the properties. The changes are saved instantly when the behavior is reactive.
code .
If you get an error, you might need to install the code command in PATH.
TypeScript is the primary language for building SharePoint client-side web parts. TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. SharePoint client-side
development tools are built using TypeScript classes, modules, and interfaces to help developers build robust client-side web parts.
The following are some key files in the project.
This property definition is used to define custom property types for your web part, which is described in the property pane section later.
Web part render method
The DOM element where the web part should be rendered is available in the render method. This method is used to render the web part inside that DOM element. In the HelloWorld web
part, the DOM element is set to a DIV. The method parameters include the display mode (either Read or Edit) and the configured web part properties if any:
This model is flexible enough so that web parts can be built in any JavaScript framework and loaded into the DOM element.
Configure the Web part property pane
The property pane is defined in the HelloWorldWebPart class. The propertyPaneSettings property is where you need to define the property pane.
When the properties are defined, you can access them in your web part by using this.properties.<property-value> , as shown in the render method:
<p class="${styles.description}">${escape(this.properties.description)}</p>
Notice that we are performing an HTML escape on the property's value to ensure a valid string. To learn more about how to work with the property pane and property pane field types, see
Make your SharePoint client-side web part configurable.
Let's now add a few more properties to the property pane: a check box, a drop-down list, and a toggle. We first start by importing the respective property pane fields from the framework.
1. Scroll to the top of the file and add the following to the import section from @microsoft/sp-webpart-base :
PropertyPaneCheckbox,
PropertyPaneDropdown,
PropertyPaneToggle
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
PropertyPaneCheckbox,
PropertyPaneDropdown,
PropertyPaneToggle
} from '@microsoft/sp-webpart-base';
2. Update the web part properties to include the new properties. This maps the fields to typed objects.
3. Replace the IHelloWorldWebPartProps interface with the following code.
6. After you add your properties to the web part properties, you can now access the properties in the same way you accessed the description property earlier:
To set the default value for the properties, you need to update the web part manifest's properties property bag.
7. Open HelloWorldWebPart.manifest.json and modify the properties to:
"properties": {
"description": "HelloWorld",
"test": "Multi-line text field",
"test1": true,
"test2": "2",
"test3": true
}
The web part property pane now has these default values for those properties.
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "7d5437ee-afc2-4e66-914b-80be5ace4056",
"alias": "HelloWorldWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "HelloWorld" },
"description": { "default": "HelloWorld description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "HelloWorld",
"test": "Multi-line text field",
"test1": true,
"test2": "2",
"test3": true
}
}]
}
Now that we have introduced new properties, ensure that you are again hosting the web part from the local development environment by executing the following command. This also
ensures that the previous changes were correctly applied.
gulp serve
NOTE
If you do not have the SPFx developer certificate installed, Workbench notifies you that it is configured not to load scripts from localhost. Stop the currently running process in the
console window, and execute the gulp trust-dev-cert command in your project directory console to install the developer certificate before running the gulp serve command again.
2. Notice that the SharePoint Workbench now has the Office 365 Suite navigation bar.
3. Select the add icon in the canvas to reveal the toolbox. The toolbox now shows the web parts available on the site where the SharePoint Workbench is hosted along with your
HelloWorldWebPart.
4. Add HelloWorld from the toolbox. Now you're running your web part in a page hosted in SharePoint!
NOTE
The color of the web part depends on the colors of the site. By default, web parts inherit the core colors from the site by dynamically referencing Office UI Fabric Core styles used in the site
where the web part is hosted.
Because you are still developing and testing your web part, there is no need to package and deploy your web part to SharePoint.
Next steps
Congratulations on getting your first Hello World web part running!
Now that your web part is running, you can continue building out your Hello World web part in the next topic, Connect your web part to SharePoint. You will use the same Hello World web
part project and add the ability to interact with SharePoint List REST APIs. Notice that the gulp serve command is still running in your console window (or in Visual Studio Code if you are
using that as editor). You can continue to let it run while you go to the next article.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, please report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your
input in advance.
Connect your client-side web part to SharePoint (Hello World part 2)
5/3/2018 • 9 minutes to read Edit Online
Connect your web part to SharePoint to access functionality and data in SharePoint and provide a more integrated experience for end users. This article continues building the Hello World
web part built in the previous article Build your first web part.
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/hYrP6D4FaaU
cd helloworld-webpart
gulp serve
this.context.pageContext
2. Switch to Visual Studio code (or your preferred IDE) and open src\webparts\helloWorld\HelloWorldWebPart.ts.
3. Inside the render method, replace the innerHTML code block with the following code:
this.domElement.innerHTML = `
<div class="${ styles.helloWorld }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">Welcome to SharePoint!</span>
<p class="${ styles.subTitle }">Customize SharePoint experiences using web parts.</p>
<p class="${ styles.description }">${escape(this.properties.description)}</p>
<p class="${ styles.description }">${escape(this.properties.test)}</p>
<p class="${ styles.description }">Loading from ${escape(this.context.pageContext.web.title)}</p>
<a href="https://aka.ms/spfx" class="${ styles.button }">
<span class="${ styles.label }">Learn more</span>
</a>
</div>
</div>
</div>
</div>`;
4. Notice how ${ } is used to output the variable's value in the HTML block. An extra HTML p is used to display this.context.pageContext.web.title . Because this web part loads
from the local environment, the title is Local Workbench.
5. Save the file. The gulp serve running in your console detects this save operation and:
Builds and bundles the updated code automatically.
Refreshes your local Workbench page (as the web part code needs to be reloaded).
NOTE
Keep the console window and Visual Studio Code side-by-side to see gulp automatically compile as you save changes in Visual Studio Code.
6. In your browser, switch to the local SharePoint Workbench tab. If you have already closed the tab, the URL is https://localhost:4321/temp/workbench.html .
You should see the following in the web part:
7. Navigate to the SharePoint Workbench hosted in SharePoint. The full URL is https://your-sharepoint-site-url/_layouts/workbench.aspx . Notice that on the SharePoint Online side,
you need to refresh the page to see the changes.
NOTE
If you do not have the SPFx developer certificate installed, Workbench notifies you that it is configured not to load scripts from localhost. Execute gulp trust-dev-cert command in
your project directory console to install the developer certificate.
You should now see your SharePoint site title in the web part now that page context is available to the web part.
Define list model
You need a list model to start working with SharePoint list data. To retrieve the lists, you need two models.
1. Switch to Visual Studio Code and go to src\webparts\helloWorld\HelloWorldWebPart.ts.
2. Define the following interface models just above the HelloWorldWebPart class:
The ISPList interface holds the SharePoint list information that we are connecting to.
3. Add the following private method that mocks the list retrieval inside the HelloWorldWebPart class.
private _getMockListData(): Promise<ISPLists> {
return MockHttpClient.get()
.then((data: ISPList[]) => {
var listData: ISPLists = { value: data };
return listData;
}) as Promise<ISPLists>;
}
SharePoint Framework includes a helper class spHttpClient to execute REST API requests against SharePoint. It adds default headers, manages the digest needed for writes, and collects
telemetry that helps the service to monitor the performance of an application.
To use this helper class, import them from the @microsoft/sp-http module
1. Scroll to the top of the HelloWorldWebPart.ts file.
2. Copy and paste the following code just under import MockHttpClient from './MockHttpClient'; :
import {
SPHttpClient,
SPHttpClientResponse
} from '@microsoft/sp-http';
3. Add the following private method to retrieve lists from SharePoint inside the HelloWorldWebPart class.
The method uses the spHttpClient helper class and issues a get request. It uses the ISPLists model and also applies a filter to not retrieve hidden lists.
4. Save the file.
5. Switch to the console window that is running gulp serve and check if there are any errors. If there are errors, gulp reports them in the console, and you need to fix them before
proceeding.
.list {
color: #333333;
font-family: 'Segoe UI Regular WestEuropean', 'Segoe UI', Tahoma, Arial, sans-serif;
font-size: 14px;
font-weight: normal;
box-sizing: border-box;
margin: 10;
padding: 10;
line-height: 50px;
list-style-type: none;
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.listItem {
color: #333333;
vertical-align: center;
font-family: 'Segoe UI Regular WestEuropean', 'Segoe UI', Tahoma, Arial, sans-serif;
font-size: 14px;
font-weight: normal;
box-sizing: border-box;
margin: 0;
padding: 0;
box-shadow: none;
*zoom: 1;
padding: 9px 28px 3px;
position: relative;
}
import {
Environment,
EnvironmentType
} from '@microsoft/sp-core-library';
2. Add the following private method inside the HelloWorldWebPart class to call the respective methods to retrieve list data:
The previous method references the new CSS styles added earlier by using the styles variable.
5. Save the file.
this.domElement.innerHTML = `
<div class="${ styles.helloWorld }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">Welcome to SharePoint!</span>
<p class="${ styles.subTitle }">Customize SharePoint experiences using web parts.</p>
<p class="${ styles.description }">${escape(this.properties.description)}</p>
<p class="${ styles.description }">${escape(this.properties.test)}</p>
<p class="${ styles.description }">Loading from ${escape(this.context.pageContext.web.title)}</p>
<a href="https://aka.ms/spfx" class="${ styles.button }">
<span class="${ styles.label }">Learn more</span>
</a>
</div>
</div>
<div id="spListContainer" />
</div>
</div>`;
this._renderListAsync();
4. Switch to the Workbench hosted in SharePoint. Refresh the page and add the HelloWorld web part.
You should see lists returned from the current site.
5. Now you can stop the server from running. Switch to the console and stop gulp serve . Select Ctrl+C to terminate the gulp task.
Next steps
Congratulations on connecting your web part to SharePoint list data!
You can continue building out your Hello World web part in the next topic Deploy your web part to a SharePoint page. You will learn how to deploy and preview the Hello World web part in
a SharePoint page.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Deploy your client-side web part to a SharePoint page (Hello World part 3)
5/3/2018 • 4 minutes to read Edit Online
Ensure that you have completed the procedures in the following articles before you start:
Build your first SharePoint client-side web part
Connect your client-side web part to SharePoint
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/BpJ01ahxbiY
cd helloworld-webpart
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "helloworld-webpart-client-side-solution",
"id": "4432f33b-5845-4ca0-827e-a8ae68c7b945",
"version": "1.0.0.0",
"includeClientSideAssets": true
},
"paths": {
"zippedPackage": "solution/helloworld-webpart.sppkg"
}
}
5. In the console window, enter the following command to package your client-side solution that contains the web part:
gulp package-solution
helloworld-webpart.sppkg
Package contents
The package uses SharePoint Feature to package your web part. By default, the gulp task creates a feature for your web part.
You can view the raw package contents in the sharepoint/debug folder.
The contents are then packaged into an .sppkg file. The package format is very similar to a SharePoint Add-ins package and uses Microsoft Open Packaging Conventions to package your
solution.
The JavaScript files, CSS, and other assets are packaged inside of the package when the --ship option is used. In this case, however, we will first test deployment and capabilities by hosting
JavaScript files from localhost. This deployment option is explained in the next tutorial.
NOTE
Starting from the SharePoint Framework v1.4, static assets are by default packaged inside of the sppkg package. When a package is deployed in the app catalog, the assets are automatically
hosted either from Office 365 CDN (if enabled) or from an app catalog URL. You can control this behavior with the includeClientSideAssets setting in the package-solution.json file.
If you do not have an app catalog, a SharePoint Online Admin can create one by following the instructions in this guide: Use the App Catalog to make custom business apps available for
your SharePoint Online environment.
1. Go to your site's app catalog.
2. Upload or drag and drop the helloworld-webpart.sppkg to the app catalog.
This deploys the client-side solution package. Because this is a full trust client-side solution, SharePoint displays a dialog and asks you to trust the client-side solution to deploy.
3. Select Deploy.
The client-side solution and the web part are installed on your developer site.
The Site Contents page shows you the installation status of your client-side solution. Make sure the installation is complete before going to the next step.
"internalModuleBaseUrls": [
"https://`your-local-machine-name`:4321/"
]
2. Before adding the web part to a SharePoint server-side page, run the local server.
3. In the console window that has the helloworld-webpart project directory, run the gulp task to start serving from localhost:
NOTE
This is the same property pane you built and previewed in the Workbench.
2. Edit the Description property, and enter Client-side web parts are awesome!
3. Notice that you still have the same behaviors such as a reactive pane where the web part is updated as you type.
4. Select the x icon to close the client-side property pane.
5. On the toolbar, select Save and close to save the page.
Next steps
Congratulations! You have deployed a client-side web part to a modern SharePoint page.
You can continue building out your Hello World web part in the next topic Hosting client-side web part from Office 365 CDN, where you will learn how to deploy and load the web part
assets from an Office 365 CDN instead of localhost.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Host your client-side web part from Office 365 CDN (Hello World part 4)
4/20/2018 • 6 minutes to read Edit Online
Office 365 Content Delivery Network (CDN) provides you an easy solution to host your assets directly from your own Office 365 tenant. It can be used for hosting any static assets that are
used in SharePoint Online.
NOTE
There are multiple different hosting options for your web part assets. This tutorial concentrates on showing the Office 365 CDN option, but you could also use the Azure CDN or simply host
your assets from SharePoint library from your tenant. In the latter case, you would not benefit from the CDN performance improvements, but that would also work from the functionality
perspective. Any location that end users can access using HTTP(S) would be technically suitable for hosting the assets for end users.
IM P O R T A N T
This article uses the includeClientSideAssets attribute, which was introduced in the SPFx v1.4. This version is not supported with SharePoint 2016 Feature Pack 2. If you are using an on-
premises setup, you need to decide the CDN hosting location separately. You can also simply host the JavaScript files from a centralized library in your on-premises SharePoint to which
your users have access. Please see additional considerations in the SharePoint 2016 specific guidance.
Make sure that you have completed the following tasks before you begin:
Build your first client-side web part
Connect your client-side web part to SharePoint
Deploy your client-side web part to a SharePoint page
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/MEZMs8VMVQ0
If you are using a non-Windows machine, you cannot use the SharePoint Online Management Shell. You can, however, manage these settings by using Office 365 CLI.
2. Connect to your SharePoint Online tenant with a PowerShell session.
3. Get the current status of public CDN settings from the tenant level by executing the following commands one-by-one.
SharePoint Framework solutions can automatically benefit from the Office 365 Public CDN as long as it's enabled in your tenant. When CDN is enabled, */CLIENTSIDEASSETS origin is
automatically added as a valid origin.
1. Enable public CDN in the tenant.
Now public CDN has been enabled in the tenant by using the default file type configuration allowed. This means that the following file type extensions are supported: CSS, EOT, GIF,
ICO, JPEG, JPG, JS, MAP, PNG, SVG, TTF, and WOFF.
SharePoint Framework solutions can automatically benefit from the Office 365 Public CDN as long as it's enabled in your tenant. When CDN is enabled, the */CLIENTSIDEASSETS
origin is automatically added as a valid origin.
NOTE
If you have previously enabled Office 365 CDN, you should re-enable the public CDN so that you have the */CLIENTSIDEASSETS entry added as a valid CDN origin for public CDN. If
this entry is not present and the public CDN is enabled in your tenant, bundle requests will contain the token hostname spclientsideassetlibrary in their URL, causing the requests to
fail.
3. You can double-check the current setup of your end-points. Execute the following command to get the list of CDN origins from your tenant:
Notice that your newly added origin is listed as a valid CDN origin. Final configuration of the origin takes a while (approximately 15 minutes), so we can continue by creating your test
web part, which will be hosted from the origin when the deployment is completed.
NOTE
When the origin is listed without the (configuration pending) text, it is ready to be used in your tenant. This is the indication of an on-going configuration between SharePoint Online
and the CDN system.
cd helloworld-webpart
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "helloworld-webpart-client-side-solution",
"id": "4432f33b-5845-4ca0-827e-a8ae68c7b945",
"version": "1.0.0.0",
"includeClientSideAssets": true
},
"paths": {
"zippedPackage": "solution/helloworld-webpart.sppkg"
}
}
The default value for the includeClientSideAssets is true , which means that static assets are packaged automatically inside of the .sppkg files, and you do not need to separately host your
assets from an external system.
If Office 365 CDN is enabled, it is used automatically with default settings. If Office 365 CDN is not enabled, assets are served from the app catalog site collection.
NOTE
Starting from the SharePoint Framework v1.4, static assets are by default packaged inside of the sppkg package. When a package is deployed in the app catalog, they are automatically
hosted either from Office 365 CDN (if enabled) or from an app catalog URL. You can control this behavior with the includeClientSideAssets setting in the package-solution.json file.
2. Execute the following task to package your solution. This creates an updated helloworld-webpart.sppkg package on the sharepoint/solution folder.
NOTE
If you are interested in what actually got packaged inside of the sppkg file, you can look in the content of the sharepoint/solution/debug folder.
3. Upload or drag and drop the newly created client-side solution package to the app catalog in your tenant.
4. Because you already deployed the package, you are prompted as to whether to replace the existing package. Select Replace It.
5. Notice how the domain list in the prompt says SharePoint Online. This is because the content is either served from the Office 365 CDN or from the app catalog, depending on the
tenant settings. Select Deploy.
6. Open the site where you previously installed the helloworld-webpart-client-side-solution or install the solution to a new site.
7. After the solution has been installed, select Add a page from the gear menu, and select HelloWorld from the modern page web part picker to add your custom web part to page.
8. Notice how the web part is rendered even though you are not running the node.js service locally.
9. Save changes on the page with the web part.
10. Select F12 to open up developer tools.
11. Extend publiccdn.sharepointonline.com under the source and notice how the hello-world-web-part file is loaded from the Public CDN URL pointing dynamically to a library
located under the app catalog site collection.
NOTE
If you would not have CDN enabled in your tenant, and the includeClientSideAssets setting would be true in the package-solution.json, the loading URL for the assets would be
dynamically updated and pointing directly to the ClientSideAssets folder located in the app catalog site collection. In this example case, the URL would be
https://sppnp.microsoft.com/sites/apps/ClientSideAssets/ .
Now you have deployed your custom web part to SharePoint Online and it's being hosted automatically from the Office 365 CDN.
Next steps
You can load jQuery and jQuery UI and build a jQuery Accordion web part. To continue, see Add jQueryUI Accordion to your client-side web part.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Add jQueryUI Accordion to your SharePoint client-side web part
4/20/2018 • 7 minutes to read Edit Online
Adding the jQueryUI Accordion to your web part project involves creating a new web part, as shown in the following image.
Ensure that you've completed the following steps before you start:
Build your first web part
Connect your web part to SharePoint
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/7UOxTbMMPrQ
The developer toolchain uses Webpack, SystemJS, and CommonJS to bundle your web parts. This includes loading any external dependencies such as jQuery or jQueryUI. To load external
dependencies, at a high level, you need to:
Acquire the external library, either via npm or download from the vendor.
If available, install the respective framework's TypeScript type definitions.
If required, update your solution config to not include the external dependency in your web part bundle by default.
W A R N IN G
Make sure to create this directory in a new folder, not as a subdirectory of helloworld-webpart .
2. Go to the project directory:
cd jquery-webpart
3. Create a new jQuery web part by running the Yeoman SharePoint Generator:
yo @microsoft/sharepoint
4. When prompted:
Accept the default jquery-webpart as your solution name. and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Enter jQuery for the web part name, and select Enter.
Enter jQuery Web Part as the description of the web part, and select Enter.
Accept the default No JavaScript framework option for the framework, and select Enter to continue.
At this point, Yeoman installs the required dependencies and scaffolds the solution files. This might take a few minutes. Yeoman scaffolds the project to include your jQueryWebPart
as well.
6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:
npm shrinkwrap
7. Enter the following to open the web part project in Visual Studio Code:
code .
Next, we need to install the typings for our project. Starting from TypeScript 2.0, we can use npm to install needed typings.
3. Open your console and install the needed types:
"bundles": {
"j-query-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/jQuery/JQueryWebPart.js",
"manifest": "./src/webparts/jQuery/JQueryWebPart.manifest.json"
}
]
}
},
2. The externals section contains the libraries that are not bundled with the default bundle.
"externals": {},
3. To exclude jQuery and jQueryUI from the default bundle, add the modules to the externals section:
"jquery":"node_modules/jquery/dist/jquery.min.js",
"jqueryui":"node_modules/jqueryui/jquery-ui.min.js"
Now when you build your project, jQuery and jQueryUI are not bundled into your default web part bundle.
The full content of the config.json file is currently as follows:
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"j-query-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/jQuery/JQueryWebPart.js",
"manifest": "./src/webparts/jQuery/JQueryWebPart.manifest.json"
}
]
}
},
"externals": {
"jquery":"node_modules/jquery/dist/jquery.min.js",
"jqueryui":"node_modules/jqueryui/jquery-ui.min.js"
},
"localizedResources": {
"JQueryWebPartStrings": "lib/webparts/jQuery/loc/{locale}.js"
}
}
2. Load some external CSS files by using the module loader. Add the following import:
3. Load the jQueryUI styles in the JQueryWebPart web part class by adding a constructor and using the newly imported SPComponentLoader. Add the following constructor to your web
part:
public constructor() {
super();
SPComponentLoader.loadCss('//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css');
}
To render Accordion
1. In the jQueryWebPart.ts , go to the render method.
2. Set the web part's inner HTML to render the accordion HTML:
this.domElement.innerHTML = MyAccordionTemplate.templateHtml;
3. jQueryUI Accordion has a few options that you can set to customize the accordion. Define a few options for your accordion just under
this.domElement.innerHTML = MyAccordionTemplate.templateHtml; :
As you can see, the jQueryUI typed definition allows you to create a typed variable called JQueryUI.AccordionOptions and specify the supported properties.
If you play around with the IntelliSense, you notice that you get full support for available methods under JQueryUI. as well as the method parameters.
4. Finally, initialize the accordion:
jQuery('.accordion', this.domElement).accordion(accordionOptions);
As you can see, you use the variable jQuery that you used to import the jquery module. You then initialize the accordion.
The complete render method looks like this:
jQuery('.accordion', this.domElement).accordion(accordionOptions);
}
gulp serve
NOTE
Visual Studio Code provides built-in support for gulp and other task runners. You can select Ctrl+Shift+B in Windows or Cmd+Shift+B on a Mac to debug and preview your web
part.
Gulp executes the tasks and opens the local SharePoint web part Workbench.
2. In the page canvas, select the + (plus sign) to show the list of web parts, and add the jQuery web part. You should now see the jQueryUI Accordion!
3. In the console where you have gulp serve running, select Ctrl+C to terminate the task.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Use Office UI Fabric React components in your SharePoint client-side web part
5/3/2018 • 5 minutes to read Edit Online
This article describes how to build a simple web part that uses the DocumentCard component of Office UI Fabric React. Office UI Fabric React is the front-end framework for building
experiences for Office and Office 365. Fabric React includes a robust collection of responsive, mobile-first components that make it easy for you to create web experiences by using the Office
Design Language.
The following image shows a DocumentCard component created with Office UI Fabric React.
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/1YRu4-nZot4
md documentcardexample-webpart
cd documentcardexample-webpart
3. Make sure you have the latest version of @microsoft/generator-sharepoint installed and create a new web part by running the Yeoman SharePoint generator:
yo @microsoft/sharepoint
4. When prompted:
Accept the default documentcardexample-webpart as your solution name, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Use DocumentCardExample for your web part name, and select Enter.
Accept the default DocumentCardExample description, and select Enter.
Select React as the framework, and select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files. This might take a few minutes. Yeoman scaffolds the project to include your
DocumentCardExample web part as well.
6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:
npm shrinkwrap
7. Next, enter the following to open the web part project in Visual Studio Code:
code .
You now have a web part project with the React framework.
8. Open DocumentCardExampleWebPart.ts from the src\webparts\documentCardExample folder.
As you can see, the render method creates a react element and renders it in the web part DOM.
With the current release of the SharePoint Framework, we recommend that you use the Office UI Fabric and Fabric React that ships with the generator. We don't recommend that you update
the Office UI Fabric and Fabric React packages independently because that might conflict with the already available version in SharePoint, and as a result, your web part may fail to function
as expected.
3. Delete the current render method, and add the following updated render method:
return (
<DocumentCard onClickHref='http://bing.com'>
<DocumentCardPreview { ...previewProps } />
<DocumentCardTitle title='Revenue stream proposal fiscal year 2016 version02.pptx' />
<DocumentCardActivity
activity='Created Feb 23, 2016'
people={
[
{ name: 'Kat Larrson', profileImageSrc: String(require('./avatar-kat.png')) }
]
}
/>
</DocumentCard>
);
}
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
if (build.getConfig().production) {
var basePath = build.writeManifests.taskConfig.cdnBasePath;
if (!basePath.endsWith('/')) {
basePath += '/';
}
generatedConfiguration.output.publicPath = basePath;
}
else {
generatedConfiguration.output.publicPath = "/dist/";
}
return generatedConfiguration;
}
});
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
if (build.getConfig().production) {
var basePath = build.writeManifests.taskConfig.cdnBasePath;
if (!basePath.endsWith('/')) {
basePath += '/';
}
generatedConfiguration.output.publicPath = basePath;
}
else {
generatedConfiguration.output.publicPath = "/dist/";
}
return generatedConfiguration;
}
});
build.initialize(gulp);
gulp serve
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
See also
Build your first SharePoint client-side web part
Provision SharePoint assets from your SharePoint client-side web part
7/9/2018 • 12 minutes to read Edit Online
SharePoint assets can be provisioned as part of the SharePoint Framework solution, and are deployed to SharePoint sites when the solution is installed on it.
Before you start, complete the procedures in the following articles to ensure that you understand the basic flow of creating a custom client-side web part:
Build your first web part
Connect your web part to SharePoint
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/qAqNk_X82QM
md asset-deployment-webpart
cd asset-deployment-webpart
3. Create a new client-side web part solution by running the Yeoman SharePoint Generator:
yo @microsoft/sharepoint
4. When prompted:
Accept the default asset-deployment-webpart as your solution name, and then select Enter.
Select SharePoint Online only (latest), and then select Enter.
Select Use the current folder as the location for the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Enter AssetDeployment for the web part name, and then select Enter.
Enter AssetDeployment Web Part as the description of the web part, and then select Enter.
Accept the default No JavaScipt web framework option for the framework, and then select Enter to continue.
At this point, Yeoman installs the required dependencies and scaffolds the solution files. This might take a few minutes. Yeoman scaffolds the project to include your
AssetDeployment web part as well.
6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:
npm shrinkwrap
7. Next, enter the following to open the web part project in Visual Studio Code:
code .
<Field ID="{060E50AC-E9C1-4D3C-B1F9-DE0BCAC300F6}"
Name="SPFxAmount"
DisplayName="Amount"
Type="Currency"
Decimals="2"
Min="0"
Required="FALSE"
Group="SPFx Columns" />
<Field ID="{943E7530-5E2B-4C02-8259-CCD93A9ECB18}"
Name="SPFxCostCenter"
DisplayName="Cost Center"
Type="Choice"
Required="FALSE"
Group="SPFx Columns">
<CHOICES>
<CHOICE>Administration</CHOICE>
<CHOICE>Information</CHOICE>
<CHOICE>Facilities</CHOICE>
<CHOICE>Operations</CHOICE>
<CHOICE>Sales</CHOICE>
<CHOICE>Marketing</CHOICE>
</CHOICES>
</Field>
<ContentType ID="0x010042D0C1C200A14B6887742B6344675C8B"
Name="Cost Center"
Group="SPFx Content Types"
Description="Sample content types from web part solution">
<FieldRefs>
<FieldRef ID="{060E50AC-E9C1-4D3C-B1F9-DE0BCAC300F6}" />
<FieldRef ID="{943E7530-5E2B-4C02-8259-CCD93A9ECB18}" />
</FieldRefs>
</ContentType>
<ListInstance
CustomSchema="schema.xml"
FeatureId="00bfea71-de22-43b2-a848-c05709900100"
Title="SPFx List"
Description="SPFx List"
TemplateType="100"
Url="Lists/SPFxList">
</ListInstance>
</Elements>
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "asset-deployment-webpart-client-side-solution",
"id": "6690f11b-012f-4268-bc33-3086eb2dd287",
"version": "1.0.0.0",
"includeClientSideAssets": true
},
"paths": {
"zippedPackage": "solution/asset-deployment-webpart.sppkg"
}
}
2. To ensure that our newly added Feature Framework files are taken into account while the solution is being packaged, we need to include a Feature Framework feature definition for
the solution package. Let's include a JSON definition for the needed feature inside of the solution structure as demonstrated in the following code.
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "asset-deployment-webpart-client-side-solution",
"id": "6690f11b-012f-4268-bc33-3086eb2dd287",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"features": [{
"title": "asset-deployment-webpart-client-side-solution",
"description": "asset-deployment-webpart-client-side-solution",
"id": "523fe887-ced5-4036-b564-8dad5c6c6e24", // <-- Update 'id' with a new GUID
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
],
"elementFiles":[
"schema.xml"
]
}
}]
},
"paths": {
"zippedPackage": "solution/asset-deployment-webpart.sppkg"
}
}
gulp bundle
gulp package-solution
asset-deployment-webpart.sppkg
3. Before testing the package in SharePoint, let's quickly have a look on the default structures created for the package around the defined feature framework elements. Move back to the
Visual Studio Code side and expand the sharepoint/solution/debug folder, which contains the raw XML structures to be included in the actual sppkg package.
4. Deploy the package that was generated to the app catalog. Go to your tenant's app catalog.
5. Upload or drag and drop the asset-deployment-webpart.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint displays a dialog and asks you to trust the
client-side solution to deploy.
NOTE
SharePoint validates the published package when it's deployed and you only see the trust dialog if the package is valid for deployment. You can also see the status around this
validation from the 'Valid App Package' column in the app catalog.
6. Go to the site where you want to test the SharePoint asset provisioning. This could be any site collection in the tenant where you deployed this solution package.
7. Select the gears icon on the top nav bar on the right, and then select Add an app to go to your Apps page.
8. In the Search box, enter deployment, and then select Enter to filter your apps.
9. Select the asset-deployment-webpart-client-side-solution app to install the app on the site. When installation is completed, refresh the page by selecting F5. Notice how the
custom SPFx List has been provisioned to site as part of the solution package deployment.
10. Select SPFx List to move to the list. Notice how the custom fields Amount and Cost Center are visible automatically in the default view of the list.
You can read more details around the Feature Framework upgrade action definitions at SharePoint Add-ins update process.
<ListInstance
FeatureId="00bfea71-de22-43b2-a848-c05709900100"
Title="New List"
Description="New list provisioned from v2"
TemplateType="100"
Url="Lists/NewList">
</ListInstance>
</Elements>
4. We also need a definition for actual Feature Framework upgrade actions, so create a new file inside the sharepoint\assets folder named upgrade-actions-v2.xml.
5. Copy the following XML structure into upgrade-actions-v2.xml. Notice that the feature GUID reference in the path refers to the automatically created folder under the
sharepoint/solution/debug folder and has to be updated based on your solution. This GUID also matches the GUID of the feature, which we defined in the package-solution.json
file.
<ApplyElementManifests>
<ElementManifest Location="523fe887-ced5-4036-b564-8dad5c6c6e24\elements-v2.xml" />
</ApplyElementManifests>
The solution version indicates for SharePoint that there's a new version of the SharePoint Framework solution available. The feature version ensures that the upgrade actions are executed
accordingly when the solution package is upgraded in the existing site(s).
1. Open package-solution.json from the config folder and update the version values for both the solution and the feature to "2.0.0.0".
2. We also need to include elements-v2.xml under the elementManifest section, and need to include the upgradeActions element with a pointer to the just created upgrade-actions-
v2.xml file.
Here's a complete package-solution.json file with needed changes. Notice that identifiers for your solution could be slightly different, so concentrate on adding only the missing
pieces.
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "asset-deployment-webpart-client-side-solution",
"id": "6690f11b-012f-4268-bc33-3086eb2dd287",
"version": "2.0.0.0",
"includeClientSideAssets": true,
"features": [{
"title": "asset-deployment-webpart-client-side-solution",
"description": "asset-deployment-webpart-client-side-solution",
"id": "523fe887-ced5-4036-b564-8dad5c6c6e24",
"version": "2.0.0.0",
"assets": {
"elementManifests": [
"elements.xml",
"elements-v2.xml"
],
"elementFiles":[
"schema.xml"
],
"upgradeActions":[
"upgrade-actions-v2.xml"
]
}
}]
},
"paths": {
"zippedPackage": "solution/asset-deployment-webpart.sppkg"
}
}
IM P O R T A N T
Notice that we also included the elements-v2.xml under the elementManifest section. This ensures that when you install this package to a clean site as a version 2.0, the end result
will match the upgraded packages.
3. In the console window, enter the following command to re-package your client-side solution that contains the web part so that we get the basic structure ready for packaging:
gulp bundle
gulp package-solution
The command creates a new version of the solution package in the sharepoint/solution folder. Notice that you can easily confirm from the sharepoint/solution/debug folder that the
updated XML files are included in the solution package.
5. Next you need to deploy the new version that was generated to the app catalog. Go to your tenant's app catalog.
6. Upload or drag and drop the asset-deployment-webpart.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint requests that you confirm overriding the
existing version.
This presents the current details around the installed SharePoint Framework solution. This page also now shows the text as 'There is a new version of this app. Get it now' to indicate
that there's a new version available.
4. Select the GET IT button to start the update process for the package.
If you move to the classic experience, you can see more details on the actual upgrade action being applied for the SharePoint Framework solution.
NOTE
Because the SharePoint Framework uses the same app infrastructure as SharePoint Add-ins, the status for the upgrade indicates that the update can happen for an add-in or an app.
The update can take a while, but when the solution status changes to normal again, you can select F5 to refresh the site contents page to confirm that a new list called New List has
been successfully provisioned as part of the update process.
Now we have successfully upgraded this instance to the latest version. This Feature Framework option for SharePoint asset provisioning is pretty much the same as it is for the
SharePoint Add-in model. The key difference is that the assets are being provisioned directly to a normal SharePoint site, because there's no concept called app or add-in web with
SharePoint Framework solutions.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
See also
Provision SharePoint assets with your solution package
Sample solution - Deployment of SharePoint assets as part of SPFx package
Deploy your SharePoint client-side web part to Azure CDN
3/26/2018 • 7 minutes to read Edit Online
Create a new sample web part and deploy its assets to an Azure Content Delivery Network (CDN) instead of using the default Office 365 CDN as the hosting solution. You'll use an Azure
Storage account integrated with a CDN to deploy your assets. SharePoint Framework build tools provide out-of-the-box support for deploying to an Azure Storage account; however, you
can also manually upload the files to your favorite CDN provider or to SharePoint.
NOTE
There are multiple different hosting options for your web part assets. This tutorial concentrates on showing the Azure CDN option, but you could also use the Office 365 CDN or simply host
your assets from SharePoint library from your tenant. In the latter case, you would not benefit from the CDN performance improvements, but that would also work from the functionality
perspective. Any location that end users can access by using HTTP would be technically suitable for hosting the assets for end users.
You need to create a unique storage account name for your own SharePoint Framework projects.
For example, in the following screenshot, spfxsamples is the endpoint name, Storage is the origin type, and spfxsamples.blob.core.windows.net is the storage account.
Because you associated the CDN endpoint with your storage account, you can also access the BLOB container at the following URL: http://spfxsamples.azureedge.net/azurehosted-webpart/
Note, however, that you have not yet deployed the files.
md azurehosted-webpart
cd azurehosted-webpart
yo @microsoft/sharepoint
4. When prompted:
Accept the default azurehosted-webpart as your solution name, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select y to use the tenant-scoped deployment option, which makes the web part available across sites immediately when it's deployed.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Use AzureCDN for your web part name, and select Enter.
Accept the default AzureCDN description as your web part description, and select Enter.
Accept the default No javascript web framework as the framework you would like to use, and select Enter.
At this point, Yeoman scaffolds the solution files and installs the required dependencies. This might take a few minutes. Yeoman scaffolds the project to include your custom web part
as well.
6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:
npm shrinkwrap
7. Enter the following to open the web part project in Visual Studio Code:
code .
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "azurehosted-webpart-client-side-solution",
"id": "a4e95ed1-d096-4573-8a57-d0cc3b52da6a",
"version": "1.0.0.0",
"includeClientSideAssets": false,
"skipFeatureDeployment": true
},
"paths": {
"zippedPackage": "solution/azurehosted-webpart.sppkg"
}
}
NOTE
The skipFeatureDeployment setting is here true because the answer for the tenant-scope deployment option was said to be 'y' in the Yeoman flow. This means that you do NOT need
to explicitly install the solution to the site before the web part is available. Deploying and approving the solution package in the tenant app catalog is sufficient to make the web part
available across all the sites in the given tenant.
2. Replace the account, container, accessKey with your storage account name, BLOB container, and storage account access key respectively.
workingDir is the directory where the web part assets are located.
In this example, with the storage account created earlier, this file will look like:
{
"workingDir": "./temp/deploy/",
"account": "spfxsamples",
"container": "azurehosted-webpart",
"accessKey": "q1UsGWocj+CnlLuv9ZpriOCj46ikgBbDBCaQ0FfE8+qKVbDTVSbRGj41avlG73rynbvKizZpIKK9XpnpA=="
}
{
"cdnBasePath": "<!-- PATH TO CDN -->"
}
In this example, with the CDN profile created earlier, this file will look like:
{
"cdnBasePath": "https://spfxsamples.azureedge.net/azurehosted-webpart/"
}
NOTE
The CDN base path is the CDN endpoint with the BLOB container.
3. Save the file.
This builds the minified assets required to upload to the CDN provider. The --ship indicates the build tool to build for distribution. You should also notice that the output of the build
tools indicate the Build Target is SHIP.
gulp deploy-azure-storage
This deploys the web part bundle along with other assets such as JavaScript and CSS files to the CDN.
This creates the updated client-side solution package in the sharepoint\solution folder.
To upload to your app catalog
1. Upload or drag and drop the client-side solution package to the app catalog. Notice how the URL is pointing to the Azure CDN URL configured in the previous steps.
2. Select the check box to indicate that the solution can be deployed automatically across all sites in the organization.
3. Select Deploy.
The app catalog now has the client-side solution package where the web part bundle is loaded from the CDN.
3. Notice that you are not running gulp serve, and therefore nothing is served from localhost. Content is served from the Azure CDN. You can also double-check this by selecting F12
in your browser and confirming that you can see the Azure CDN as one of the sources for the page assets.
As long as you are updating the cdnBasePath accordingly, your files are being properly loaded.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
See also
Build your first SharePoint client-side web part
Integrate web part properties with SharePoint
3/26/2018 • 4 minutes to read Edit Online
When building classic web parts, web part properties were isolated from SharePoint, and their values were managed by end-users. SharePoint Framework offers you a new set of
capabilities that simplify managing web part properties' values and integrate them with SharePoint Search. This article explains how you can use these capabilities when building SharePoint
Framework client-side web parts.
IM P O R T A N T
The following guide applies only to SharePoint Framework client-side web parts placed on modern SharePoint pages. Capabilities described in this article don't apply to classic web parts or
SharePoint Framework client-side web parts placed on classic pages.
Before accepting values for web part properties from end users, you should always validate them. This not only allows you to ensure that your web parts are user-friendly, but also helps you
prevent storing invalid data in the web part's configuration.
Additionally, you should consider that the SharePoint Framework doesn't support personalization, and all users see the same configuration of the particular web part.
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
IWebPartPropertiesMetadata
} from '@microsoft/sp-webpart-base';
// ...
The propertiesMetadata method returns an object, where the property is a string and specifies the name of the web part property, and the value is an object specifying how SharePoint
should handle that particular property.
When overriding the propertiesMetadata method, you don't have to list all the web part properties. By default, web part properties' values are not processed by SharePoint, and you
should include only those properties that you want to be processed.
Following is the list of possible values that can be set in the properties metadata and their impact on how the value of the web part property is processed by SharePoint.
none (default) no no no
isSearchablePlainText yes no no
IM P O R T A N T
When defining the configuration for your web part properties, you should use only one of the properties mentioned in the table for each web part property. Setting multiple properties will
most likely lead to undesirable results, and you should avoid it.
By default the value of a web part property is not indexed by SharePoint Search and it's not processed by SharePoint in any way. It's passed to the web part exactly how it's been entered by
the user configuring the web part.
If you specify the web part property as isSearchablePlainText , it is included in the full-text Search index. Whenever users search for any keywords included in the value of that property,
SharePoint Search returns the page with the web part in the search results. If the value contains a link to a document stored in SharePoint, that link won't be updated if the referenced
document is moved or renamed. Also, any HTML entered by users, is kept intact. When working with the value of such a property, you should treat it as plain-text and escape HTML that
might be entered by users before rendering it on the page to avoid script injection.
When a web part property is defined as isHtmlString , SharePoint first of all removes any unsafe HTML, such as script tags, from the property value. The HTML that remains can be
considered safe to render on a page. If the value contains any URLs pointing to files stored in SharePoint, as soon as one of these files is renamed or moved, SharePoint automatically
updates the URL stored in the web part property. This significantly simplifies managing URLs across all web parts and pages in your tenant. HTML web part properties are also searchable,
so users can look for any keywords included in the property value.
Property value types isImageSource and isLink are meant to be used for web part properties that include nothing else but a link to an image or a file stored in SharePoint. In both cases,
SharePoint Search includes the content in the full-text index and keeps the specified URL up to date in case the referenced file is renamed or moved. Additionally, image sources may get
additional processing to help images download faster. If the page has a title image, and the image is among the first five images on the page, or the image is in the first two rows on the page,
the image is preloaded.
Make your SharePoint client-side web part configurable
3/26/2018 • 2 minutes to read Edit Online
The property pane allows end users to configure the web part with several properties. The article Build your first web part describes how the property pane is defined in the
HelloWorldWebPart class. The property pane properties are defined in propertyPaneSettings.
A property pane has three key metadata: a page, an optional header, and at least one group.
Pages provide you the flexibility to separate complex interactions and put them into one or more pages. Pages contain a header and groups.
Headers allow you to define the title of the property pane.
Groups allow you to define the various sections or fields for the property pane through which you want to group your field sets.
The following figure shows an example of a property pane in SharePoint.
import {
PropertyPaneTextField,
PropertyPaneCheckbox,
PropertyPaneLabel,
PropertyPaneLink,
PropertyPaneSlider,
PropertyPaneToggle,
PropertyPaneDropdown
} from '@microsoft/sp-webpart-base';
PropertyPaneTextField('targetProperty',{
//field properties are defined here
})
The targetProperty defines the associated object for that field type and is also defined in the props interface in your web part.
To assign types to these properties, define an interface in your web part class that includes one or more target properties.
When the properties are defined, you can access them in your web part by using the this.properties.[property-name]. For more information, see render method of the
HelloWorldWebPart.
See also
SharePoint Framework Overview
Configure web part icon
3/26/2018 • 4 minutes to read Edit Online
Selecting an icon that illustrates the purpose of your SharePoint client-side web part makes it easier for users to find your web part among other all web parts available in the toolbox.
2. When adding your web part to the page, the selected icon is displayed in the toolbox.
The big benefit of this approach is that you don't need to deploy the icon image file along with your web part assets. Additionally, on computers using different DPI or other accessibility
settings, the icon automatically adapts to these settings without losing quality.
2. The web part icon image displayed in the toolbox is 40x28px. If your image is bigger, it is sized proportionally to match these dimensions.
While using custom images gives you more flexibility to choose an icon for your web part, it requires you to deploy them along with your other web part assets. Additionally, your image
might lose quality when displayed in higher DPI or specific accessibility settings. To avoid quality loss, you can use vector-based SVG images, which are also supported by the SharePoint
Framework.
Base64 encoding works for both bitmap images, such as PNG, as well as vector SVG images. The big benefit of using base64-encoded images is that you don't need to deploy the web part
icon image separately.
Additional considerations
Each web part must have an icon. If you specify the web part icon by using both the officeFabricIconFontName and the iconImageUrl properties, the icon specified in the
officeFabricIconFontName is used.
If you choose not to use an Office UI Fabric icon, you have to specify a URL in the iconImageUrl property.
See also
SharePoint Framework Overview
Use web parts with the full-width column
4/10/2018 • 2 minutes to read Edit Online
Modern SharePoint pages support layouts that allow users to organize the information they present on their pages. Users can choose from a number of different section layouts such as two
columns, three columns, or one-third column. Modern pages in communication sites offer an additional section layout named Full-width column. This layout spans the full width of the
page without any horizontal margin or padding. SharePoint Framework web parts can be placed in any layout, but due to extra requirements, web parts must explicitly enable support for the
full-width column.
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "34f6d7f2-262f-460a-8b65-152d784127cb",
"alias": "HelloWorldWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"supportsFullBleed": true,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "HelloWorld" },
"description": { "default": "HelloWorld description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "HelloWorld"
}
}]
}
With this setting enabled, when you edit a page with a full-width column layout, your web part will be displayed among the web parts that can be added to the column.
At this time, the SharePoint Workbench doesn't support testing web parts in the full-width column layout. Instead, you will have to deploy your web part to a developer tenant, create a
communication site, and test your web part there.
Hide a web part from the toolbox
6/12/2018 • 2 minutes to read Edit Online
For scenarios where you automatically instantiate a custom web part on a modern page, you might want the web part not to be manually available for end-users. This could for example be a
status web part on a home page.
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "34f6d7f2-262f-460a-8b65-152d784127cb",
"alias": "HelloWorldWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"hiddenFromToolbox": true,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "HelloWorld" },
"description": { "default": "HelloWorld description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "HelloWorld"
}
}]
}
With the hiddenFromToolbox setting enabled, when you edit a page, the web part will not be listed in the toolbox.
Simplify adding web parts with preconfigured entries
5/3/2018 • 14 minutes to read Edit Online
More complex SharePoint Framework client-side web parts likely have many properties that the user must configure. You can help users by adding preconfigured property entries for
specific scenarios. A preconfigured entry initializes the web part with pre-set values.
NOTE
Before following the steps in this article, be sure to set up your SharePoint client-side web part development environment.
{
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
"id": "6737645a-4443-4210-a70e-e5e2a219133a",
"alias": "GalleryWebPart",
"componentType": "WebPart",
"version": "0.0.1",
"manifestVersion": 2,
"preconfiguredEntries": [{
"groupId": "1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489", // Discover
"group": { "default": "Under Development" },
"title": { "default": "Gallery" },
"description": { "default": "Shows items from the selected list" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "Gallery"
}
}]
}
The preconfiguredEntries property provides information about your web part for use in the web part toolbox. When users add web parts to the page, the information from the
preconfiguredEntries property is used to display the web part in the toolbox and define its default settings when it's added to the page.
If you've built classic web parts with full-trust solutions, you can think of each entry in the preconfiguredEntries array as corresponding to a .webpart file. Just like a .webpart file, each
entry in the preconfiguredEntries property is linked to the web part code and specifies basic information about the web part, such as its title or description as well as default values for its
properties.
title ILocalizedString yes The web part title that is displayed in "title": { "default": "Weather",
the toolbox. "nl-nl": "Weerbericht" }
description ILocalizedString yes The web part description that is "description": { "default":
displayed in the toolbox tooltips. "Shows weather in the given
location", "nl-nl": "Toont
weerbericht voor de opgegeven
locatie" }
officeFabricIconFontName string no The icon for the web part that is "officeFabricIconFontName":
displayed in the toolbox. Its value must "Sunny"
be one of the Office UI Fabric icon
names. If this property has a value, the
iconImageUrl property is ignored.
iconImageUrl string no The icon for the web part that is "iconImageUrl":
displayed in the toolbox and is "https://cdn.contoso.com/weather.png"
represented by an image URL. The
image at the URL must be exactly
40x28 px. If the
officeFabricIconName property does
not have a value, this property must
have a value.
group ILocalizedString no The group name in the web part picker "group": { "default": "Content",
to contain the web part in the classic "nl-nl": "Inhoud" }
page. If no value is provided, the web
part is displayed in the Miscellaneous
group.
dataVersion string no Use this field to specify the data "dataVersion": "1.0"
version of the pre-configured data
provided to the web part. Note that
data version is different from the
version field in the manifest. The
manifest version is used to control the
versioning of the web part code, while
data version is used to control the
versioning of the serialized data of the
web part. Refer to the dataVersion field
of your web part for more information.
Supported values format:
MAJOR.MINOR version
properties TProperties yes A key-value pair object with default "properties": { "location":
values for web part properties. "Redmond", "numberOfDays": 3,
"showIcon": true }
Some web part properties have a value of type ILocalizedString. This type is a key-value pair object that allows developers to specify strings for the different locales. At a minimum, a value
of type ILocalizedString must contain the default value.
Optionally, developers can provide the translations of that value to the different locales that their web part supports. If the web part is placed on a page in a locale that isn't listed in the
localized string, the default value is used instead.
Valid ILocalizedString values:
"title": {
"default": "Weather",
"nl-nl": "Weerbericht"
}
"title": {
"default": "Weather"
}
An ILocalizedString value that is not valid because the default key is missing:
"title": {
"en-us": "Weather"
}
Text, media, and content cf066440-0614-43d6-98ae-0b31cf14c7c3 Web parts that display text, multi-media, documents, information
from the web, and other rich content.
Discover 1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489 Web parts that organize, group, and filter content to help users
discover information.
Communication and collaboration 75e22ed5-fa14-4829-850a-c890608aca2d Web parts that facilitate information sharing, team work, and social
interactions.
Planning and process 1bc7927e-4a5e-4520-b540-71305c79c20a Web parts that empower team productivity with the use of planning
and process tools.
Business and intelligence 4aca9e90-eff5-4fa1-bac7-728f5f157b66 Web parts for tracking and analyzing data, and for integrating
business flow with pages.
Site tools 070951d7-94da-4db8-b06e-9d581f1f55b1 Web parts for site information and management.
If the developer fills an ID not in the previous list, the web part falls back to the Other group.
To see how you can use preconfigured entries when building web parts, you will build a sample gallery web part. Using several properties, users can configure this web part to show items
from a selected list in a specific way. For brevity, you will omit the actual implementation of the web part logic and will focus on using the preconfiguredEntries property to provide
preconfigured versions of the gallery web part.
Create a new web part project
1. Start by creating a new folder for your project.
md react-preconfiguredentries
cd react-preconfiguredentries
3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project.
yo @microsoft/sharepoint
npm shrinkwrap
6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor you prefer.
When building SharePoint Framework client-side web parts using React, after changing the web part properties interface, you need to update the web part's render method that uses
that interface to create an instance of the main React component.
4. In the code editor, open the ./src/webparts/gallery/GalleryWebPart.ts file. Change the web part render method to:
ReactDom.render(element, this.domElement);
}
// ...
}
5. Update the main React component to display the values of the properties. If the web part hasn't been configured, show the standard web part placeholder. In the code editor, open the
./src/webparts/gallery/components/Gallery.tsx file, and change its code to:
import * as React from 'react';
import styles from './Gallery.module.scss';
import { IGalleryProps } from './IGalleryProps';
6. Update the main React component interface to match the web part property interface, because we are bypassing all the web part properties to this component. In the code editor,
open the ./src/webparts/gallery/components/IGalleryProps.ts file, and change its code to:
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneDropdown,
PropertyPaneSlider,
PropertyPaneChoiceGroup
} from '@microsoft/sp-webpart-base';
In a real-life scenario, you would retrieve the list of lists from the current SharePoint site. For brevity, in this example, you use a fixed list instead.
2. Add the missing resource strings by opening the ./src/webparts/gallery/loc/en-us.js file and changing its code to:
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListNameFieldLabel": "List",
"OrderFieldLabel": "Items order",
"OrderFieldChronologicalOptionLabel": "chronological",
"OrderFieldReversedOptionLabel": "reversed chronological",
"NumberOfItemsFieldLabel": "Number of items to show",
"StyleFieldLabel": "Items display style",
"StyleFieldThumbnailsOptionLabel": "thumbnails",
"StyleFieldListOptionLabel": "list"
}
});
gulp serve
4. In the web browser, add the web part to the canvas and open its property pane. You should see all the properties available for users to configure.
Because you didn't specify any default values for the web part, every time users add the web part to the page, they have to configure it first. You can simplify this experience by providing
default values for the most common scenarios.
{
// ...
"preconfiguredEntries": [{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Recent images" },
"description": { "default": "Shows 5 most recent images" },
"officeFabricIconFontName": "Picture",
"properties": {
"listName": "Images",
"order": "reversed",
"numberOfItems": 5,
"style": "thumbnails"
}
}]
}
NOTE
If you were debugging the project previously, stop debugging and start it again. Changes made to the web part manifest are not automatically reflected in the Workbench while
debugging, and you have to rebuild the project to see them.
3. When you open the web part toolbox to add the web part to the canvas, you see that its name and icon changed to reflect the preconfigured settings.
4. After adding the web part to the page, it works immediately by using the preconfigured settings.
2. Notice how you keep the previous preconfigured entry intact and add another one next to it by using different values for properties.
3. To see the result, start debugging the project by running the following command:
gulp serve
4. When you open the web part toolbox to add the web part to the canvas, you see that there are two web parts for you to choose from.
5. After adding the Recent documents web part to the page, it works immediately by using its specific preconfigured settings.
Specify an unconfigured instance of the web part
When building web parts, there are often specific scenarios that the web part should support. Providing preconfigured entries for those scenarios makes it easier for users to use the web
part.
Depending on how you build your web part, it could be possible that the web part can support other unforeseen scenarios as well. If you only provide specific preconfigured entries, users
might not realize they can use your web part for a different scenario. It might be a good idea to provide a generic unconfigured variant of your web part as well.
1. In the code editor, open the ./src/webparts/gallery/GalleryWebPart.manifest.json file. Change the preconfiguredEntries property to:
{
// ...
"preconfiguredEntries": [{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Recent images" },
"description": { "default": "Shows 5 most recent images" },
"officeFabricIconFontName": "Picture",
"properties": {
"listName": "Images",
"order": "reversed",
"numberOfItems": 5,
"style": "thumbnails"
}
},
{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Recent documents" },
"description": { "default": "Shows 10 most recent documents" },
"officeFabricIconFontName": "Documentation",
"properties": {
"listName": "Documents",
"order": "reversed",
"numberOfItems": 10,
"style": "list"
}
},
{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Gallery" },
"description": { "default": "Shows items from the selected list" },
"officeFabricIconFontName": "CustomList",
"properties": {
"listName": "",
"order": "",
"numberOfItems": 5,
"style": ""
}
}]
}
2. Notice that the generic unconfigured version of the web part is added next to the configurations that target specific scenarios. This way, if there is no specific configuration addressing
users' needs, they can always use the generic version and configure it according to their requirements.
3. To see the result, start debugging the project by running the following command:
gulp serve
4. When you open the web part toolbox to add the web part to the canvas, you see that there are now three web parts that users can choose from.
Validate web part property values
3/26/2018 • 9 minutes to read Edit Online
When working with SharePoint Framework client-side web parts, users can configure them to meet their needs by using their properties. By validating the provided configuration values, you
can make it easier for users to configure the web part and improve the overall user experience of working with your web part.
NOTE
Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.
md react-listinfo
cd react-listinfo
3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project.
yo @microsoft/sharepoint
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:
npm shrinkwrap
6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.
Options for validating web part properties
SharePoint Framework offers developers two ways to validate values of web part properties. You can validate the value directly, inside a web part's code, or you can call an external API to
perform the validation there.
Validating values inline is useful for performing simple validations such as minimal/maximum length, required properties, or simple pattern recognition, like a zip code. Whenever the
validation is based on business logic, such as checking a social security number or a security group membership, calling external APIs is a better approach.
To validate the value of a web part property, you have to implement the event handler for the onGetErrorMessage event of that particular property. For inline validation, the event handler
should return a string with the validation error or an empty string if the provided value is valid.
For validation using remote APIs, the event handler returns a promise of string. If the provided value is invalid, the promise resolves with the error message. If the provided value is valid, the
promise resolves with an empty string.
return '';
}
}
The validateDescription method checks if the description is provided, and if it isn't longer than 40 characters. If the provided description is invalid, the method returns an error
message corresponding to the validation error. If the provided value is correct, it returns an empty string.
2. Associate the validateDescription method with the description web part property. In the ListInfoWebPart class, change the implementation of the
getPropertyPaneConfiguration method to:
export default class ListInfoWebPart extends BaseClientSideWebPart<IListInfoWebPartProps> {
// ...
// ...
}
You have extended the definition of the description web part by defining the validateDescription method as the event handler for the onGetErrorMessage event.
3. Run the following command to see the result of the validation:
gulp serve
4. In the Workbench, add the web part to the canvas and open its properties. If you remove the description, you should see the first validation error.
5. Provide a value that's longer than 40 characters. You should see another validation error displayed under the text field.
6. Notice that when providing an invalid value, the web part is rendered showing the last valid value. Additionally, in the non-reactive property pane mode, if one of the web part
properties is invalid, the Apply button is disabled, preventing the user from applying the invalid configuration.
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"preconfiguredEntries": [{
"groupId": "1ec8f92d-ea55-4584-bf50-bac435c916bf",
"group": { "default": "Under Development" },
"title": { "default": "List info" },
"description": { "default": "Shows information about the selected list" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "List info"
}
}]
}
2. In the code editor, open the ./src/webparts/listInfo/IListInfoWebPartProps.ts file, and extend the interface definition with the listName property of type string.
3. Finish adding the new web part property by opening the ./src/webparts/listInfo/ListInfoWebPart.ts file in the code editor, and changing the implementation of the
getPropertyPaneConfiguration method to:
// ...
}
4. Add the missing ListNameFieldLabel resource string by changing the code of the ./src/webparts/listInfo/loc/mystrings.d.ts file to:
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field",
"ListNameFieldLabel": "List name"
}
});
6. Run the following command to verify that the project is running and that the newly added list name property is displayed in the web part property pane:
gulp serve
Validate the name of the list by using the SharePoint REST API
In this step, you validate the provided list name and check if it corresponds to an existing list on the current SharePoint site.
1. In the code editor, open the ./src/webparts/listInfo/ListInfoWebPart.ts file, and add the following references:
2. In the ListInfoWebPart class, add the validateListName method with the following code:
First, the validateListName method checks if a list name has been provided. If not, it resolves the promise with a relevant validation error. If the user has provided a list name, the
validateListName method uses the SPHttpClient to call the SharePoint REST API and check if the list with the specified name exists.
If the list with the specified name exists on the current site, the response returns a 200 OK status code, and the validateListName method resolves the promise with an empty string,
confirming that the provided value represents a valid list.
If the list with the specified name doesn't exist, the response returns a different code. Typically, it is a 404 Not Found response, but if the request failed in some other way, a different
status code can be returned. In both cases, the validateListName method displays a relevant error message to the user.
With the list name validation method defined, the next step is to configure it as the validation handler for the listName web part property.
3. In the ListInfoWebPart class, replace the code of the getPropertyPaneConfiguration method with:
export default class ListInfoWebPart extends BaseClientSideWebPart<IListInfoWebPartProps> {
// ...
// ...
}
Because the list name validation method communicates with the SharePoint REST API, you have to test the web part in the hosted version of the SharePoint workbench.
5. Add the web part to the canvas and open its properties. Because you haven't specified a default value for the list name, which is a required property, you see a validation error.
If you provide the name of a list that doesn't exist, the web part displays a validation error stating that the list you specified doesn't exist in the current site.
If you specify the name of an existing list, the validation error disappears.
// ...
}
2. The deferredValidationTime property specifies the number of milliseconds that the SharePoint Framework waits before starting the validation process.
3. Run the following command to see that the applied delay is working as expected:
When building client-side web parts, loading data once and reusing it across different web parts helps you improve the performance of your pages and decrease the load on your network.
This article describes a number of approaches that you can use to share data across multiple web parts.
A sample service responsible for loading the data could look like the following:
import { IDocument } from './IDocument';
SharePoint Framework client-side web parts would consume this service by using the following code:
DocumentsService.getRecentDocuments(this.properties.startFrom)
.then((documents: IDocument[]): void => {
const element: React.ReactElement<IRecentDocumentsProps> = React.createElement(
RecentDocuments,
{
documents: documents
}
);
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
});
}
// ...
}
To improve the loading time of the page and decrease the traffic on your network, you can build your web parts in such a way that they load the data only once. Whenever one of the web
parts on the page requests a specific set of data, it reuses data loaded previously if possible.
Globally-scoped variables are generally a bad idea. However, for illustration and simplicity purposes, we are using them here as "demo code." There are many patterns around this issue,
including importing/exporting modules by using TypeScript concepts.
Web parts built using the SharePoint Framework are isolated into separate modules. This way, one web part cannot directly access data and properties stored by another web part. One way
to overcome this design characteristic and make data loaded by one web part available to other web parts on the page is to assign the retrieved data to a globally-scoped variable.
Using the data access service shown earlier, it could be changed as follows:
import { IDocument } from './IDocument';
if ((window as any).loadingData) {
// data is being loaded, wait a moment and try again
window.setTimeout((): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments);
});
}, 100);
}
else {
(window as any).loadingData = true;
// data not loaded yet, call the remote API,
// store the data for subsequent requests, and resolve the Promise
(window as any).loadedData = loadedData;
(window as any).loadingData = false;
resolve((window as any).loadedData);
}
});
}
}
Notice how loading the data has been moved from the specific methods to the ensureRecentDocuments method. If the data has been loaded previously, the method resolves the promise
immediately by returning the previously loaded documents. If the data is currently being loaded, the method waits for 100 ms and tries resolving the promise again.
If you look at the log in the developer tools, you notice that the remote API is now called only once.
Looking at the informational messages, you can confirm that when the second web part tries to load the data, it detects that the data is already being loaded. After the data is loaded, it reuses
the existing data rather than loading it itself.
Using a globally-scoped variable is the easiest way to exchange data between different web parts on the page. One downside of using this approach, however, is that the data is exposed not
only to web parts but also to all other elements on the page. This introduces the risk of other elements on the page using the same variable as you to store their data, potentially overwriting
your data.
if ((window as any).loadingData) {
// data is being loaded, wait a moment and try again
window.setTimeout((): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments);
});
}, 100);
}
else {
(window as any).loadingData = true;
// data not loaded yet, call the remote API,
// store the data for subsequent requests, and resolve the Promise
Cookies.set(DocumentsService.cookieName, loadedData, {
expires: 1,
path: '/'
});
(window as any).loadingData = false;
resolve(loadedData);
}
});
}
}
In the previous example, the js-cookie package is used to simplify working with cookies. Using the parameters passed into the Cookies.set() method, you can specify to which pages and for
how long the retrieved data should be available.
When you load the page in Microsoft Edge for the first time, you see that the data is retrieved once and reused by both web parts.
On subsequent requests, a web part can directly reuse the previously loaded data without calling the remote API.
When loading the page in Google Chrome, you see that the data is loaded twice from the remote API and is not being cached at all.
Different web browsers have different limits regarding how much data can be stored in a cookie. In this example, the retrieved data exceeds the maximum length of what can be stored in a
cookie in Google Chrome. As a result, no cookie is being set and the data is loaded twice.
While you could use cookies to share data between web parts, assuming the data that you want to share is not too large, there are some downsides to using cookies. Similar to globally-
scoped variables, cookies are available to all elements on the page, or even across the whole portal, and could be overwritten by them. Additionally, web browsers send cookies with outgoing
requests and retrieve them with incoming responses, which adds overhead to loading information in the portal. Another important thing that you should consider is that cookies are
persisted in the web browser, and you should never store any confidential information in them.
if ((window as any).loadingData) {
// data is being loaded, wait a moment and try again
window.setTimeout((): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments);
});
}, 100);
}
else {
(window as any).loadingData = true;
// data not loaded yet, call the remote API,
// store the data for subsequent requests, and resolve the Promise
if (localStorage) {
localStorage.setItem(DocumentsService.storageKey, JSON.stringify(loadedData));
}
(window as any).loadingData = false;
resolve(loadedData);
}
});
}
}
The implementation of this service is very similar to when using cookies. One thing that you should keep in mind, however, is that browser storage can be disabled by the user, and you
should always check for its availability before performing operations on it. Just as with cookies, local storage is persisted in the web browser and you should never use it to store any
confidential information.
See also
Tutorial: Share data between web parts by using a global variable
Share data between web parts by using a global variable (tutorial)
5/3/2018 • 18 minutes to read Edit Online
When building client-side web parts, loading data once and reusing it across different web parts helps improve the performance of your pages and decrease the load on your network.
NOTE
Before following the steps in this article, be sure to set up your SharePoint client-side web part development environment.
md react-recentdocuments
cd react-recentdocuments
3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:
yo @microsoft/sharepoint
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:
npm shrinkwrap
6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.
Show the recently modified documents
The Recent Documents web part shows information about the most recently modified documents displayed as cards by using Office UI Fabric.
2. Remove the standard description property from the web part manifest. Open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.manifest.json file, and from
the properties property, remove the description property:
{
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
"id": "7a7e3aa9-5d8a-4155-936b-0b0e06e9ca11",
"alias": "RecentDocumentsWebPart",
"componentType": "WebPart",
"version": "0.0.1",
"manifestVersion": 2,
"preconfiguredEntries": [{
"groupId": "7a7e3aa9-5d8a-4155-936b-0b0e06e9ca11",
"group": { "default": "Under Development" },
"title": { "default": "Recent documents" },
"description": { "default": "Shows recently modified documents" },
"officeFabricIconFontName": "Page",
"properties": {
}
}]
}
3. Remove the standard description property from the web part. In the code editor, open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.ts file, and replace its
render method with the following code:
ReactDom.render(element, this.domElement);
}
// ...
}
2. In the code editor, open the ./src/webparts/recentDocuments/components/RecentDocuments.tsx file, and paste the following code:
First, the component iterates through the documents passed by using its documents property. For each document, it builds an Office UI Fabric DocumentCard, filling its properties with the
relevant information about that particular document. Finally, when cards for all documents have been built, the component adds them to its body and returns the complete markup.
2. In the RecentDocumentsWebPart class, add a new private variable named documents by using the following code:
export default class RecentDocumentsWebPart extends BaseClientSideWebPart<IRecentDocumentsWebPartProps> {
private static documents: IDocument[] = [
{
title: 'Proposal for Jacksonville Expansion Ad Campaign',
url: 'https://contoso-my.sharepoint.com/personal/miriamg_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BCBF65183-0378-485B-AB67-791E0FC81D72%7D&file=Jacksonville%2
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=ca6fa69c-347d-4c07-886c-67105dc5a357&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BCBF6
iconUrl: '',
activity: {
title: 'Modified, January 25 2017',
actorName: 'Miriam Graham',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/[email protected]&size=L'
}
},
{
title: 'Customer Feedback for ZT1000',
url: 'https://contoso-my.sharepoint.com/personal/miriamg_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7B5449CE24-BFB7-442E-843D-E0C86CEB71CC%7D&file=Customer%20Fee
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=ca6fa69c-347d-4c07-886c-67105dc5a357&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7B5449
iconUrl: '',
activity: {
title: 'Modified, January 23 2017',
actorName: 'Miriam Graham',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/[email protected]&size=L'
}
},
{
title: 'Asia Q3 Marketing Overview',
url: 'https://contoso-my.sharepoint.com/personal/alexw_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BFD077A94-AB7D-45F9-A810-36229E518A94%7D&file=Asia%20Q3%20Mark
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=18231116-2bf0-474c-93ee-eb362681b293&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BFD07
iconUrl: '',
activity: {
title: 'Modified, January 23 2017',
actorName: 'Alex Wilber',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/[email protected]&size=L'
}
},
{
title: 'Trey Research Business Development Plan',
url: 'https://contoso.sharepoint.com/sites/contoso/Resources/Document%20Center/_layouts/15/WopiFrame.aspx?sourcedoc=%7B743A6C44-D3F8-4ECC-A1B7-EA9844911314%7D&file=Trey%20Research%
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=923a6ce1-7b67-4bd0-a59f-89d37f233804&guidWeb=c12486eb-661c-46c7-baba-073a8a45b610&guidFile=%7B743A
iconUrl: '',
activity: {
title: 'Modified, January 15 2017',
actorName: 'Alex Wilber',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/[email protected]&size=L'
}
},
{
title: 'XT1000 Marketing Analysis',
url: 'https://contoso-my.sharepoint.com/personal/henriettam_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BA8B9F935-E5A1-47AD-B052-D5ED30E682AB%7D&file=XT1000%20Ma
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=b187e1dd-7687-49e0-87ff-6250e61e56ac&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BA8B9
iconUrl: '',
activity: {
title: 'Modified, December 15 2016',
actorName: 'Henrietta Mueller',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/[email protected]&size=L'
}
}
];
// ...
}
3. Change the render method to load and render the information about the recently modified documents:
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
}, 300);
}
// ...
}
4. Verify that the web part is working correctly and shows information about the three most recently modified documents by running the following command from a command prompt
in your project directory:
gulp serve
5. In the SharePoint Workbench, add the Recent Documents web part to the canvas.
Show the most recently modified document
The Recent Document web part shows information about the most recently modified document.
2. Remove the standard description property from the web part manifest. Open the ./src/webparts/recentDocument/RecentDocumentWebPart.manifest.json file, and from the
properties property, remove the description property:
{
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
"id": "71a6f643-1ac1-47ee-a9f1-502ef52f26d4",
"alias": "RecentDocumentWebPart",
"componentType": "WebPart",
"version": "0.0.1",
"manifestVersion": 2,
"preconfiguredEntries": [{
"groupId": "71a6f643-1ac1-47ee-a9f1-502ef52f26d4",
"group": { "default": "Under Development" },
"title": { "default": "Recent document" },
"description": { "default": "Shows information about the most recently modified document" },
"officeFabricIconFontName": "Page",
"properties": {
}
}]
}
3. Remove the standard description property from the web part property pane. In the code editor, open the ./src/webparts/recentDocument/RecentDocumentWebPart.ts file, and
replace its render method with the following code:
ReactDom.render(element, this.domElement);
}
// ...
}
Having moved the files to another location in your project, you need to update the paths where they're referenced.
2. In the code editor, open the ./src/webparts/recentDocuments/components/IRecentDocumentsProps.ts file, and change its code to:
3. Open the ./src/webparts/recentDocuments/components/RecentDocuments.tsx file, and update the import statement of the IDocument interface to:
4. Open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.ts file, and update the import statement of the IDocument interface to:
2. In the code editor, open the ./src/webparts/recentDocument/components/RecentDocument.tsx file, and paste the following code:
return (
<div className={styles.helloWorld}>
<DocumentCard onClickHref={document.url}>
<DocumentCardPreview previewImages={[{
name: document.title,
url: document.url,
previewImageSrc: document.imageUrl,
iconSrc: document.iconUrl,
imageFit: ImageFit.cover,
width: 318,
height: 196,
accentColor: '#ce4b1f'
}]} />
<DocumentCardTitle
title={document.title}
shouldTruncate={true} />
<DocumentCardActivity
activity={document.activity.title}
people={
[
{ name: document.activity.actorName, profileImageSrc: document.activity.actorImageUrl }
]
}
/>
</DocumentCard>
</div>
);
}
}
The RecentDocument React component uses the information about the most recently modified document passed in the document property to render an Office UI Fabric DocumentCard.
2. In the RecentDocumentWebPart class, add a new private variable named document by using the following code:
// ...
}
3. Change the render method to load and render the information about the most recently modified document:
export default class RecentDocumentsWebPart extends BaseClientSideWebPart<IRecentDocumentsWebPartProps> {
// ...
public render(): void {
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'documents');
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
}, 300);
}
// ...
}
4. Verify that the web part is working correctly and shows information about the most recently modified document by running the following command from a command prompt in your
project folder:
gulp serve
5. In the SharePoint Workbench, add the Recent Document web part to the canvas.
The current implementation is a typical example of two web parts being developed independently. If they were both placed on the same page and were loading data from SharePoint, they
would execute two separate requests to retrieve similar information. If, at some point, you had to change where the information about the recently modified documents is loaded from, you
would have to update both web parts.
To improve the performance of loading the page and simplify maintaining the web part code, you can centralize the logic of retrieving the data and make the once retrieved data available to
both web parts.
The DocumentsService class is a sample service that loads information about recent documents. In this example, it uses a static data set, but you could easily change its implementation to
load its data from a SharePoint document library. At this stage, the DocumentsService class offers a centralized point for all web parts to access their data, but it doesn't store the previously
loaded data. You will implement that later in this tutorial.
With this barrel defined, other elements in the project can reference any of the exported types by using the relative path to the ./src/services/documentsService folder instead of the exact
path to the individual files. For example, the IDocument interface can be referenced like this:
import { IDocument } from '../services/documentsService';
instead of:
If at some point you decided that it's better to move the IDocument.ts file to a subfolder or merge a few files together, the only thing that you would change is the path in the barrel
definition (./src/services/documentsService/index.ts). All elements in the project could still use the exact same relative path to the documentsService folder to reference the IDocument
interface.
2. Open the ./src/webparts/recentDocuments/components/RecentDocuments.tsx file, and change the import statement of the IDocument interface to:
3. Open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.ts file, and change the import statement of the IDocument interface to:
2. Open the ./src/webparts/recentDocument/components/RecentDocument.tsx file, and change the import statement of the IDocument interface to:
3. Open the ./src/webparts/recentDocument/RecentDocumentWebPart.ts file, and change the import statement of the IDocument interface to:
4. Verify that your changes work as expected, by running the following command from a command prompt in your project folder:
gulp serve
Load web part data by using the data service
With the data service ready, the next step is to refactor both web parts to use the data service to load their data.
Load information about the recently modified documents
1. In the code editor, open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.ts file. Expand the import statement referencing the IDocument interface to:
DocumentsService.getRecentDocuments()
.then((documents: IDocument[]): void => {
const element: React.ReactElement<IRecentDocumentsProps> = React.createElement(
RecentDocuments,
{
documents: documents
}
);
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
});
}
// ...
}
DocumentsService.getRecentDocument()
.then((document: IDocument): void => {
const element: React.ReactElement<IRecentDocumentProps> = React.createElement(
RecentDocument,
{
document: document
}
);
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
});
}
// ...
}
3. Confirm that both web parts are working correctly by running the following command from a command prompt in your project folder:
gulp serve
if ((window as any).loadingData) {
// data is being loaded. wait a moment and try again
window.setTimeout((): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments);
});
}, 100);
}
else {
(window as any).loadingData = true;
window.setTimeout((): void => {
// store the data for subsequent requests and resolve the Promise
(window as any).loadedData = DocumentsService.documents;
(window as any).loadingData = false;
resolve((window as any).loadedData);
}, 300);
}
});
}
}
The first time a web part calls the data service to load its data, the service sets the loadingData global variable to true . This indicates that data is currently being loaded. This is
required to prevent data from being loaded multiple times should, for instance, another web part request loading its data while the initial request to load data has not yet completed. In
this example, the data is loaded from a static data set, but you could easily change the implementation to load the data from a SharePoint document library.
After the data is loaded, it is stored in the loadedData global variable. The value of the loadingData variable is set to false and the promise is resolved with the retrieved data. The
next time a web part requests its data, the data service returns the data loaded previously, eliminating any additional requests to the remote APIs.
2. Confirm that both web parts are working correctly by running the following command from a command prompt in your project folder:
gulp serve
3. If you were to add logging statements in the different parts of the DocumentsService.ensureRecentDocuments method, you would see that the data is loaded once and reused for the
second web part.
See also
Share data between client-side web parts
Build custom controls for the property pane
5/3/2018 • 18 minutes to read Edit Online
The SharePoint Framework contains a set of standard controls for the property pane. But sometimes you need additional functionality beyond the basic controls. You might need
asynchronous updates to the data on a control or a specific user interface. Build a custom control for the property pane to get the functionality you need.
In this article, you will build a custom dropdown control that loads its data asynchronously from an external service without blocking the user interface of the web part.
Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.
md react-custompropertypanecontrol
cd react-custompropertypanecontrol
3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:
yo @microsoft/sharepoint
npm shrinkwrap
6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.
ReactDom.render(element, this.domElement);
}
// ...
}
6. In the src/webparts/listItems/loc/en-us.js file, add the missing definition for the ListFieldLabel string.
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListFieldLabel": "List"
}
});
7. In the src/webparts/listItems/components/ListItems.tsx file, change the contents of the render method to:
gulp serve
10. In the web browser, add the List items web part to the canvas and open its properties. Verify that the value set for the List property is displayed in the web part body.
In drop 6 of the SharePoint Framework, there is a bug in the Office UI Fabric React Dropdown component that causes the control built in this article to work incorrectly. A temporary
workaround is to edit the node_modules/@microsoft/office-ui-fabric-react-bundle/dist/office-ui-fabric-react.bundle.js file and change line 12027 from:
isDisabled: this.props.isDisabled !== undefined ? this.props.isDisabled : this.props.disabled
to:
2. Define asynchronous dropdown React component properties. In the src/controls/PropertyPaneAsyncDropdown/components folder, create a new file named
IAsyncDropdownProps.ts, and enter the following code:
The IAsyncDropdownProps class defines properties that can be set on the React component used by the custom property pane control:
The label property specifies the label for the dropdown control.
The function associated with the loadOptions delegate is called by the control to load the available options.
The function associated with the onChanged delegate is called after the user selects an option in the dropdown.
The selectedKey property specifies the selected value, which can be a string or a number.
The disabled property specifies if the dropdown control is disabled or not.
The stateKey property is used to force the React component to re-render.
3. Define asynchronous dropdown React component interface. In the src/controls/PropertyPaneAsyncDropdown/components folder, create a new file named
IAsyncDropdownState.ts, and enter the following code:
this.state = {
loading: false,
options: undefined,
error: undefined
};
}
this.props.loadOptions()
.then((options: IDropdownOption[]): void => {
this.setState({
loading: false,
error: undefined,
options: options
});
}, (error: any): void => {
this.setState((prevState: IAsyncDropdownState, props: IAsyncDropdownProps): IAsyncDropdownState => {
prevState.loading = false;
prevState.error = error;
return prevState;
});
});
}
return (
<div>
<Dropdown label={this.props.label}
disabled={this.props.disabled || this.state.loading || this.state.error !== undefined}
onChanged={this.onChanged.bind(this)}
selectedKey={this.selectedKey}
options={this.state.options} />
{loading}
{error}
</div>
);
}
The AsyncDropdown class represents the React component used to render the asynchronous dropdown property pane control:
When the component first loads, the componentDidMount method, or its disabled or stateKey properties, change, and it loads the available options by calling the
loadOptions method passed through the properties.
After the options are loaded, the component updates its state showing the available options.
The dropdown itself is rendered by using the Office UI Fabric React dropdown component.
When the component is loading the available options, it displays a spinner by using the Office UI Fabric React spinner component.
The next step is to define the custom property pane control. This control is used inside the web part when defining properties in the property pane, and renders using the previously defined
React component.
Add asynchronous dropdown property pane control
1. Define asynchronous dropdown property pane control properties. A custom property pane control has two sets of properties.
The first set of properties are exposed publicly and are used to define the web part property inside the web part. These properties are component-specific properties, such as the label
displayed next to the control, minimum and maximum values for a spinner, or available options for a dropdown. When defining a custom property pane control, the type describing
these properties must be passed as the TProperties type when implementing the IPropertyPaneField<TProperties> interface.
The second set of properties are private properties used internally inside the custom property pane control. These properties have to adhere to the SharePoint Framework APIs for
the custom control to render correctly. These properties must implement the IPropertyPaneCustomFieldProps interface from the @microsoft/sp-webpart-base package.
2. Define the public properties for the asynchronous dropdown property pane control. In the src/controls/PropertyPaneAsyncDropdown folder, create a new file named
IPropertyPaneAsyncDropdownProps.ts, and enter the following code:
While the IPropertyPaneAsyncDropdownInternalProps interface doesn't define any new properties, it combines the properties from the previously defined
IPropertyPaneAsyncDropdownProps interface and the standard SharePoint Framework IPropertyPaneCustomFieldProps interface, which is required for a custom control to
run correctly.
4. Define the asynchronous dropdown property pane control. In the src/controls/PropertyPaneAsyncDropdown folder, create a new file named PropertyPaneAsyncDropdown.ts,
and enter the following code:
import * as React from 'react';
import * as ReactDom from 'react-dom';
import {
IPropertyPaneField,
PropertyPaneFieldType
} from '@microsoft/sp-webpart-base';
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
import { IPropertyPaneAsyncDropdownProps } from './IPropertyPaneAsyncDropdownProps';
import { IPropertyPaneAsyncDropdownInternalProps } from './IPropertyPaneAsyncDropdownInternalProps';
import AsyncDropdown from './components/AsyncDropdown';
import { IAsyncDropdownProps } from './components/IAsyncDropdownProps';
this.onRender(this.elem);
}
The PropertyPaneAsyncDropdown class implements the standard SharePoint Framework IPropertyPaneField interface by using the IPropertyPaneAsyncDropdownProps
interface as a contract for its public properties that can be set from inside the web part. The class contains the following three public properties defined by the IPropertyPaneField
interface:
type: Must be set to PropertyPaneFieldType.Custom for a custom property pane control.
targetProperty: Used to specify the name of the web part property to be used with the control.
properties: Used to define control-specific properties.
Notice how the properties property is of the internal IPropertyPaneAsyncDropdownInternalProps type rather than the public IPropertyPaneAsyncDropdownProps interface
implemented by the class. This is on purpose so that the properties property can define the onRender method required by the SharePoint Framework. If the onRender method was
a part of the public IPropertyPaneAsyncDropdownProps interface, when using the asynchronous dropdown control in the web part, you would be required to assign a value to it
inside the web part, which isn't desirable.
The PropertyPaneAsyncDropdown class defines a public render method, which can be used to repaint the control. This is useful in situations such as when you have cascading
dropdowns where the value set in one determines the options available in another. By calling the render method after selecting an item, you can have the dependent dropdown load
available options. For this to work, you have to make React detect that the control has changed. This is done by setting the value of the stateKey to the current date. Using this trick,
every time the onRender method is called, the component not only is re-rendered but also updates its available options.
Use the asynchronous dropdown property pane control in the web part
With the asynchronous dropdown property pane control ready, the next step is to use it inside the web part, allowing users to select a list.
Use the asynchronous dropdown property pane control to render the listName web part property
1. Reference required types. In the top section of the src/webparts/listItems/ListItemsWebPart.ts file, import the previously created PropertyPaneAsyncDropdown class by
adding:
import { PropertyPaneAsyncDropdown } from '../../controls/PropertyPaneAsyncDropdown/PropertyPaneAsyncDropdown';
2. After that code, add a reference to the IDropdownOption interface and two helpers functions required to work with web part properties.
3. Add method to load available lists. In the ListItemsWebPart class, add a method to load available lists. In this article you use mock data, but you could also call the SharePoint REST
API to retrieve the list of available lists from the current web. To simulate loading options from an external service, the method uses a two second delay.
4. Add method to handle the change of the value in the dropdown. In the ListItemsWebPart class, add a new method named onListChange.
After selecting a list in the list dropdown, the selected value should be persisted in web part properties, and the web part should be re-rendered to reflect the selected property.
5. Render the list web part property by using the asynchronous dropdown property pane control. In the ListItemsWebPart class, change the getPropertyPaneConfiguration method
to use the asynchronous dropdown property pane control to render the listName web part property.
6. At this point, you should be able to select a list by using the newly created asynchronous dropdown property pane control. To verify that the control is working as expected, open the
command-line and run:
gulp serve
Implement cascading dropdowns using the asynchronous dropdown property pane control
When building SharePoint Framework web parts, you might need to implement a configuration where the available options depend on another option chosen previously. A common
example is to first let users choose a list and from that list select a list item. The list of available items would depend on the selected list. Here is how to implement such a scenario by using
the asynchronous dropdown property pane control implemented in previous steps.
// ...
"properties": {
"listName": "",
"item": ""
}
// ...
4. In the src/webparts/listItems/ListItemsWebPart.ts file, change the code of the render method to:
ReactDom.render(element, this.domElement);
}
// ...
}
6. In the src/webparts/listItems/loc/en-us.js file, add the missing definition for the ItemFieldLabel string:
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListFieldLabel": "List",
"ItemFieldLabel": "Item"
}
});
return new Promise<IDropdownOption[]>((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => {
setTimeout(() => {
const items = {
sharedDocuments: [
{
key: 'spfx_presentation.pptx',
text: 'SPFx for the masses'
},
{
key: 'hello-world.spapp',
text: 'hello-world.spapp'
}
],
myDocuments: [
{
key: 'isaiah_cv.docx',
text: 'Isaiah CV'
},
{
key: 'isaiah_expenses.xlsx',
text: 'Isaiah Expenses'
}
]
};
resolve(items[wp.properties.listName]);
}, 2000);
});
}
}
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
new PropertyPaneAsyncDropdown('listName', {
label: strings.ListFieldLabel,
loadOptions: this.loadLists.bind(this),
onPropertyChange: this.onListChange.bind(this),
selectedKey: this.properties.listName
}),
this.itemsDropDown
]
}
]
}
]
};
}
// ...
}
The dropdown for the item property is initialized similarly to the dropdown for the listName property. The only difference is because after selecting a list, the items dropdown has to
be refreshed, an instance of the control has to be assigned to the class variable.
After selecting a list, the selected item is reset, persisted in web part properties, and reset in the items dropdown. The dropdown for selecting an item becomes enabled, and the
dropdown is refreshed in order to load its options.
2. To verify that everything is working as expected, in the command-line run:
gulp serve
After adding the web part to the page for the first time and opening its property pane, you should see both dropdowns disabled and loading their options.
After the options have been loaded, the list dropdown becomes enabled. Because no list has been selected yet, the item dropdown remains disabled.
After selecting a list in the list dropdown the item dropdown will load items available in that list.
After the available items have been loaded, the item dropdown becomes enabled.
After selecting an item in the item dropdown the web part is refreshed showing the selected item in its body.
See also
Use cascading dropdowns in web part properties
Use cascading dropdowns in web part properties
5/3/2018 • 13 minutes to read Edit Online
When designing the property pane for your SharePoint client-side web parts, you may have one web part property that displays its options based on the value selected in another property.
This scenario typically occurs when implementing cascading dropdown controls. In this article, you learn how to create cascading dropdown controls in the web part property pane without
developing a custom property pane control.
Before following the steps in this article, be sure to set up your SharePoint client-side web part development environment.
md react-cascadingdropdowns
cd react-cascadingdropdowns
3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:
yo @microsoft/sharepoint
npm shrinkwrap
6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.
ReactDom.render(element, this.domElement);
}
// ...
}
6. In the src/webparts/listItems/loc/en-us.js file, add the missing definition for the ListNameFieldLabel string:
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListNameFieldLabel": "List"
}
});
7. In the src/webparts/listItems/components/ListItems.tsx file, change the contents of the render method to:
gulp serve
10. In the web browser, add the List items web part to the canvas and open its properties. Verify that the value set for the List property is displayed in the web part body.
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
PropertyPaneDropdown,
IPropertyPaneDropdownOption
} from '@microsoft/sp-webpart-base';
2. In the ListItemsWebPart class, add a new variable named lists to store information about all available lists in the current site:
4. Change the propertyPaneSettings getter to use the dropdown control to render the listName property:
gulp serve
2. Load information about available lists into the list dropdown. In the ListItemsWebPart class, override the onPropertyPaneConfigurationStart method by using the following code:
export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
// ...
protected onPropertyPaneConfigurationStart(): void {
this.listsDropdownDisabled = !this.lists;
if (this.lists) {
return;
}
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'lists');
this.loadLists()
.then((listOptions: IPropertyPaneDropdownOption[]): void => {
this.lists = listOptions;
this.listsDropdownDisabled = false;
this.context.propertyPane.refresh();
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.render();
});
}
// ...
}
The onPropertyPaneConfigurationStart method is called by the SharePoint Framework after the web part property pane for the web part has been opened.
First, the method checks if the information about the lists available in the current site has been loaded.
If the list information is loaded, the list dropdown is enabled.
If the list information about lists has not been loaded yet, the loading indicator is displayed, which informs the user that the web part is loading information about lists.
After the information about available lists has been loaded, the method assigns the retrieved data to the lists class variable, from which it can be used by the list dropdown.
Next, the dropdown is enabled allowing the user to select a list. By calling this.context.propertyPane.refresh(), the web part property pane is refreshed and it reflects the latest
changes to the list dropdown.
After list information is loaded, the loading indicator is removed by a call to the clearLoadingIndicator method. Because calling this method clears the web part user interface, the
render method is called to force the web part to re-render.
3. Run the following command to confirm that everything is working as expected:
gulp serve
When you add a web part to the canvas and open its property pane, you should see the lists dropdown filled with available lists for the user to choose from.
Allow users to select an item from the selected list
When building web parts, you often need to allow users to choose an option from a set of values determined by a previously selected value, such as choosing a country/region based on the
selected continent, or choosing a list item from a selected list. This user experience is often referred to as cascading dropdowns. Using the standard SharePoint Framework client-side web
parts capabilities, you can build cascading dropdowns in the web part property pane. To do this, you extend the previously built web part with the ability to choose a list item based on the
previously selected list.
{
// ...
"properties": {
"listName": "",
"itemName": ""
}
// ...
}
2. Change the code in the src/webparts/listItems/IListItemsWebPartProps.ts file to:
4. In the src/webparts/listItems/ListItemsWebPart.ts file, change the code of the render method to:
ReactDom.render(element, this.domElement);
}
// ...
}
6. In the src/webparts/listItems/loc/en-us.js file, add the missing definition for the ItemNameFieldLabel string.
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListNameFieldLabel": "List",
"ItemNameFieldLabel": "Item"
}
});
2. Add a new class variable named itemsDropdownDisabled. This variable determines whether the items dropdown should be enabled or not. Users should be able to select an item
only after they selected a list.
3. Change the propertyPaneSettings getter to use the dropdown control to render the itemName property.
gulp serve
Show items available in the selected list in the item dropdown
Previously, you defined a dropdown control to render the itemName property in the web part property pane. Next, you extend the web part to load the information about items available in
the selected list, and show the items in the item dropdown.
1. Add method to load list items. In the src/webparts/listItems/ListItemsWebPart.ts file, in the ListItemsWebPart class, add a new method to load available list items from the
selected list. (Like the method for loading available lists, you use mock data.)
return new Promise<IPropertyPaneDropdownOption[]>((resolve: (options: IPropertyPaneDropdownOption[]) => void, reject: (error: any) => void) => {
setTimeout(() => {
const items = {
sharedDocuments: [
{
key: 'spfx_presentation.pptx',
text: 'SPFx for the masses'
},
{
key: 'hello-world.spapp',
text: 'hello-world.spapp'
}
],
myDocuments: [
{
key: 'isaiah_cv.docx',
text: 'Isaiah CV'
},
{
key: 'isaiah_expenses.xlsx',
text: 'Isaiah Expenses'
}
]
};
resolve(items[wp.properties.listName]);
}, 2000);
});
}
}
The loadItems method returns mock list items for the previously selected list. When no list has been selected, the method resolves the promise without any data.
2. Load information about available items into the item dropdown. In the ListItemsWebPart class, extend the onPropertyPaneConfigurationStart method to load items for the
selected list:
export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
// ...
protected onPropertyPaneConfigurationStart(): void {
this.listsDropdownDisabled = !this.lists;
this.itemsDropdownDisabled = !this.properties.listName || !this.items;
if (this.lists) {
return;
}
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'options');
this.loadLists()
.then((listOptions: IPropertyPaneDropdownOption[]): Promise<IPropertyPaneDropdownOption[]> => {
this.lists = listOptions;
this.listsDropdownDisabled = false;
this.context.propertyPane.refresh();
return this.loadItems();
})
.then((itemOptions: IPropertyPaneDropdownOption[]): void => {
this.items = itemOptions;
this.itemsDropdownDisabled = !this.properties.listName;
this.context.propertyPane.refresh();
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.render();
});
}
// ...
}
When initializing, the web part first determines if the items dropdown should be enabled or not. If the user previously selected a list, they can select an item from that list. If no list was
selected, the item dropdown is disabled.
You extended the previously defined code, which loads the information about available lists, to load the information about items available in the selected list. The code then assigns the
retrieved information to the items class variable for use by the item dropdown. Finally, the code clears the loading indicator and allows the user to start working with the web part.
3. Run the following command to confirm that everything is working as expected:
gulp serve
As required, initially the item dropdown is disabled, requiring users to select a list first. But at this point, even after a list has been selected, the item dropdown remains disabled.
4. Update web part property pane after selecting a list. When a user selects a list in the property pane, the web part should update, enabling the item dropdown and showing the list of
items available in the selected list.
In the ListItemsWebPart.ts file, in the ListItemsWebPart class, override the onPropertyPaneFieldChanged method with the following code:
export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
// ...
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
if (propertyPath === 'listName' &&
newValue) {
// push new list value
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
// get previously selected item
const previousItem: string = this.properties.itemName;
// reset selected item
this.properties.itemName = undefined;
// push new item value
this.onPropertyPaneFieldChanged('itemName', previousItem, this.properties.itemName);
// disable item selector until new items are loaded
this.itemsDropdownDisabled = true;
// refresh the item selector control by repainting the property pane
this.context.propertyPane.refresh();
// communicate loading items
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'items');
this.loadItems()
.then((itemOptions: IPropertyPaneDropdownOption[]): void => {
// store items
this.items = itemOptions;
// enable item selector
this.itemsDropdownDisabled = false;
// clear status indicator
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
// re-render the web part as clearing the loading indicator removes the web part body
this.render();
// refresh the item selector control by repainting the property pane
this.context.propertyPane.refresh();
});
}
else {
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
}
}
// ...
}
After the user selected a list, the web part persists the newly selected value. Because the selected list changed, the web part resets the previously selected list item. Now that a list is
selected, the web part property pane loads list items for that particular list. While loading items, the user shouldn't be able to select an item.
After the items for the selected list are loaded, they are assigned to the items class variable from where they can be referenced by the item dropdown. Now that the information about
available list items is available, the item dropdown is enabled allowing users to choose an item. The loading indicator is removed, which clears the web part body which is why the web
part should re-render. Finally, the web part property pane refreshes to reflect the latest changes.
NOTE
In drop 6 of the SharePoint Framework there is a bug in the Office UI Fabric React Dropdown component that causes the dropdown control to work incorrectly. A temporary
workaround is to edit the node_modules/@microsoft/office-ui-fabric-react-bundle/dist/office-ui-fabric-react.bundle.js file and change line 12027 from:
to:
See also
Build custom controls for the property pane
Migrate existing Script Editor web part customizations to the SharePoint Framework
5/3/2018 • 17 minutes to read Edit Online
SharePoint Framework is a model for building SharePoint customizations. If you have been building client-side SharePoint solutions by using the Script Editor web part, you might be
wondering what the possible advantages are of migrating them to the SharePoint Framework.
This article highlights the benefits of migrating existing client-side customizations to the SharePoint Framework and points out a number of considerations that you should take into account
when planning the migration.
NOTE
The information in this article applies to customizations built using both the Content- and the Script Editor web part. Wherever there is a reference to the Script Editor web part, you should
read Content Editor web part and Script Editor Web Part.
Similarities between SharePoint Framework solutions and Script Editor web part customizations
While built on a new development model using a new toolchain, SharePoint Framework solutions are similar to the Script Editor web part customizations you have built in the past. Because
they share the same concepts, it makes it easier for you to migrate them to the new SharePoint Framework.
Differences between SharePoint Framework solutions and Script Editor web part customizations
SharePoint customizations built using the SharePoint Framework and Script Editor web part are very similar. They all run as a part of the page under the context of the current user and are
built using client-side JavaScript. But there are also some significant differences that might influence your architectural decisions and which you should keep in mind when designing your
solution.
Distributed as packages
SharePoint client-side customizations often used SharePoint lists and libraries to store their data. When built using the Script Editor web part, there was no easy way to automatically
provision the necessary prerequisites. Deploying the same customization to another site often meant copying the web part but also correctly recreating and maintaining the necessary data
storage.
SharePoint Framework solutions are distributed as packages capable of provisioning their prerequisites, such as fields, content types, or lists, automatically. Developers building the package
can specify which artifacts are required by the solution, and whenever it's installed in a site, the specified artifacts are created. This significantly simplifies the process of deploying and
managing the solution on multiple sites.
Use TypeScript for building more robust and easier to maintain solutions
When building customizations using the Script Editor web part, citizen developers often used plain JavaScript. Often such solutions didn't contain any automated tests, and refactoring the
code was error-prone.
SharePoint Framework allows developers to benefit from the TypeScript type system when building solutions. Thanks to the type system, errors are caught during development rather than
on runtime. Also, refactoring code can be done more easily as changes to the code are safeguarded by TypeScript. Because all JavaScript is valid TypeScript, the entry barrier is low and you
can migrate your plain JavaScript to TypeScript gradually over time increasing the maintainability of your solution.
Given the variety of JavaScript libraries, there is no easy way to tell upfront if your existing scripts can be reused in a SharePoint Framework solution or if you need to rewrite it after all. The
only way to determine this is by trying to move the different pieces to a SharePoint Framework solution and see if they work as expected.
Migration tips
When transforming existing Script Editor web part customizations to the SharePoint Framework, there are a few common patterns.
Move existing code to SharePoint Framework
SharePoint customizations built using the Script Editor web part often consist of some HTML markup, included in the web part, and one or more references to JavaScript files. When
transforming your existing customization to a SharePoint Framework solution, the HTML markup from the Script Editor web part would most likely have to be moved to the render method
of the SharePoint Framework client-side web part. References to external scripts would be changed to references in the externals property in the config.json file. Internal scripts would be
copied to the web part source folder and referenced from the web part class by using require() statements.
Reference functions from script files
To reference functions from script files, these functions need to be defined as an export. Consider an existing JavaScript file that you would like to use in a SharePoint Framework client-side
web part:
To be able to call the greeting function from the web part class, you would need to change the JavaScript file to:
module.exports = {
greeting: greeting
};
Then, in the web part class, you can refer to the script and call the greeting function:
See also
Migrate SharePoint JavaScript customizations to SharePoint Framework – reference functions from script files
Migrate SharePoint JavaScript customizations to SharePoint Framework – jQuery AJAX calls and showing data
Migrate jQuery and DataTables solution built using Script Editor web part to SharePoint
Framework
5/3/2018 • 15 minutes to read Edit Online
One of the frequently used jQuery plug-ins is DataTables. With DataTables, you can easily build powerful data overviews of data coming from both SharePoint and external APIs.
The solution is built by using the standard SharePoint Script Editor web part. Following is the code used by the customization.
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.js"></script>
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" />
<table id="requests" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Business unit</th>
<th>Category</th>
<th>Status</th>
<th>Due date</th>
<th>Assigned to</th>
</tr>
</thead>
</table>
<script>
// UMD
(function(factory) {
"use strict";
if (!$) {
$ = typeof window !== 'undefined' ?
require('jquery') :
require('jquery')( root );
}
// Order and type get a number value from Moment, everything else
// sees the rendered value
return m.format(type === 'sort' || type === 'type' ? 'x' : to);
};
};
}));
</script>
<script>
$(document).ready(function() {
$('#requests').DataTable({
'ajax': {
'url': "../_api/web/lists/getbytitle('IT Requests')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title",
'headers': { 'Accept': 'application/json;odata=nometadata' },
'dataSrc': function(data) {
return data.value.map(function(item) {
return [
item.ID,
item.BusinessUnit,
item.Category,
item.Status,
new Date(item.DueDate),
item.AssignedTo.Title
];
});
}
},
columnDefs: [{
targets: 4,
render: $.fn.dataTable.render.moment('YYYY/MM/DD')
}]
});
});
</script>
First, the customization loads the libraries it uses: jQuery, DataTables, and Moment.js (lines 1-4).
Next, it specifies the structure of the table used to present the data (lines 5-16).
After creating the table, it wraps Moment.js into a DataTables plug-in so that dates displayed in the table can be formatted (first script block on lines 17-70).
Finally, the customization uses DataTables to load and present the list of IT support requests. The data is loaded by using AJAX from a SharePoint list (lines 71-96).
Thanks to using DataTables, end users get a powerful solution where they can easily filter, sort, and page through the results without any additional development effort.
Migrate the IT requests overview solution from the Script Editor web part to the SharePoint Framework
NOTE
Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.
Transforming this customization to the SharePoint Framework offers a number of benefits such as more user-friendly configuration and centralized management of the solution. Following is
a step-by-step description of how you would migrate the solution to the SharePoint Framework. First, you will migrate the solution to the SharePoint Framework with as few changes to the
original code as possible. Later, you will transform the solution's code to TypeScript to benefit from its development-time type safety features.
NOTE
The source code of the project in the different stages of migration is available at Tutorial: Migrate jQuery and DataTables solution built using Script Editor web part to SharePoint Framework
md datatables-itrequests
cd datatables-itrequests
3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:
yo @microsoft/sharepoint
npm shrinkwrap
6. Open your project folder in your code editor. In this tutorial, you will use Visual Studio Code.
{
"externals": {
"jquery": "https://code.jquery.com/jquery-1.12.4.min.js",
"datatables.net": "https://cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js",
"moment": "https://momentjs.com/downloads/moment.min.js"
}
}
2. Open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and after the last import statement add:
import 'jquery';
import 'datatables.net';
import 'moment';
// UMD
(function (factory) {
"use strict";
if (!$) {
$ = typeof window !== 'undefined' ?
require('jquery') :
require('jquery')(root);
}
// Order and type get a number value from Moment, everything else
// sees the rendered value
return m.format(type === 'sort' || type === 'type' ? 'x' : to);
};
};
}));
2. For the web part to load the plug-in, it has to reference the newly created moment-plugin.js file. In the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file,
and after the last import statement add:
import './moment-plugin';
NOTE
You don't need to include the .js extension when referencing other files. SharePoint Framework automatically resolves the extension for you.
2. To reference this file in the web part, in the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and change the render method to:
require('./script');
}
// ...
}
3. Verify that the web part is working as expected in the command line by executing:
Because the web part loads its data from SharePoint, you have to test the web part by using the hosted SharePoint Framework Workbench. Navigate to
https://yourtenant.sharepoint.com/_layouts/workbench.aspx and add the web part to the canvas. You should now see the IT requests displayed by using the DataTables jQuery plug-in.
Add support for configuring the web part through web part properties
In the previous steps, you migrated the IT requests solutions from the Script Editor web part to the SharePoint Framework. While the solution already works as expected, it doesn't use any
of the SharePoint Framework benefits. The name of the list from which IT requests are loaded is included in the code, and the code itself is plain JavaScript, which is harder to refactor than
TypeScript.
The following steps illustrate how to extend the existing solution to allow users to specify the name of the list to load the data from. Later, you transform the code to TypeScript to benefit
from its type safety features.
Define web part property for storing the name of the list
1. Define a web part property to store the name of the list from which IT requests should be loaded. In the code editor, open the
./src/webparts/itRequests/ItRequestsWebPart.manifest.json file, and rename the default description property to listName and clear its value.
2. Update the web part properties interface to reflect the changes in the manifest. In the code editor, open the ./src/webparts/itRequests/IItRequestsWebPartProps.ts file, and
change its contents to:
3. Update the display labels for the listName property. Open the ./src/webparts/itRequests/loc/mystrings.d.ts file, and change its contents to:
define([], function() {
return {
"PropertyPaneDescription": "IT Requests settings",
"BasicGroupName": "Data",
"ListNameFieldLabel": "List name"
}
});
5. Update the web part to use the newly defined property. In the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and change the
getPropertyPaneConfiguration method to:
export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> {
// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('listName', {
label: strings.ListNameFieldLabel
})
]
}
]
}
]
};
}
To prevent the web part from reloading as users type the name of the list, you also configured the web part to use the non-reactive property pane by adding the
disableReactivePropertyChanges method and setting its return value to true.
Use the configured name of the list to load the data from
Initially, the name of the list from which the data should be loaded was embedded in the REST query. Now that users can configure this name, the configured value should be injected into
the REST query before loading the data. The easiest way to do that is by moving the contents of the script.js file to the main web part file.
1. In the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and change the render method to:
$(document).ready(() => {
$('table', this.domElement).DataTable({
'ajax': {
'url': `../../_api/web/lists/getbytitle('${escape(this.properties.listName)}')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title`,
'headers': { 'Accept': 'application/json;odata=nometadata' },
'dataSrc': function (data) {
return data.value.map(function (item) {
return [
item.ID,
item.BusinessUnit,
item.Category,
item.Status,
new Date(item.DueDate),
item.AssignedTo.Title
];
});
}
},
columnDefs: [{
targets: 4,
render: $.fn.dataTable.render.moment('YYYY/MM/DD')
}]
});
});
}
// ...
}
2. Instead of referencing the code from the script.js file, all of its contents are a part of the web part's render method. In the REST query, in line 40, you can now replace the fixed name
of the list with the value of the listName property which holds the name of the list as configured by the user. Before using the value, it's being escaped by using the lodash's escape
function to disallow script injection.
At this point, the bulk of the code is still written using plain JavaScript. To avoid build issues with the $ jQuery variable, you had to define it as any type in line 18. Later, when
transforming the code to TypeScript, you replace it with a proper type definition.
As you have just moved the contents of the script.js file into the main web part file, the script.js is no longer necessary, and you can delete it from the project.
3. To verify that the web part is working as expected, run the following in the command line:
gulp serve --nobrowser
4. Navigate to the hosted Workbench and add the web part to the canvas. Open the web part property pane, specify the name of the list with IT requests, and select the Apply button to
confirm the changes.
You should now see IT requests displayed in the web part.
Type definitions for Moment.js are distributed together with the Moment.js package. Even though you're loading Moment.js from a URL, in order to use its typings, you still need to
install the Moment.js package in the project.
2. Install the Moment.js package by executing the following in the command line:
2. Having defined $ as jQuery, you can now remove the local definition of $ that you added previously:
3. Because DataTables is a jQuery plug-in that attaches itself to jQuery, you cannot load its type definition directly. Instead, you have to add it to the list of types loaded globally. In the
code editor, open the ./tsconfig.json file, and to the types array, add jquery.datatables:
{
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"types": [
"es6-promise",
"es6-collections",
"jquery.datatables",
"webpack-env"
]
}
}
interface IRequestItem {
ID: number;
BusinessUnit: string;
Category: string;
Status: string;
DueDate: string;
AssignedTo: { Title: string; };
}
2. Next, in the web part class, change the render method to:
$('table', this.domElement).DataTable({
'ajax': {
'url': `../../_api/web/lists/getbytitle('${escape(this.properties.listName)}')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title`,
'headers': { 'Accept': 'application/json;odata=nometadata' },
'dataSrc': (data: { value: IRequestItem[] }): any[][] => {
return data.value.map((item: IRequestItem): any[] => {
return [
item.ID,
item.BusinessUnit,
item.Category,
item.Status,
new Date(item.DueDate),
item.AssignedTo.Title
];
});
}
},
columnDefs: [{
targets: 4,
render: $.fn.dataTable.render.moment('YYYY/MM/DD')
}]
});
}
// ...
}
3. Notice how the AJAX request, to retrieve the data from the SharePoint list, is now typed and helps you ensure you're referring to correct properties when passing them into an array
to DataTables. The data structure used by DataTables to represent a row in the table is an array of mixed types, so for simplicity it was defined as any[]. Using the any type in this
context is not bad, because the data returned inside the dataSrc property is used internally by DataTables.
As you're updating the render method, you have also added two more changes. First, you removed the id attribute from the table. This allows you to place multiple instances of the
same web part on the page. Also, you removed the reference to the $(document).ready() function, which isn't necessary because the DOM of the element where the data table is
rendered is set before the DataTables initiation code.
/* tslint:disable:no-function-expression */
$.fn.dataTable.render.moment = function (from: string, to: string, locale: string): (d: any, type: string, row: any) => string {
/* tslint:enable */
// Argument shifting
if (arguments.length === 1) {
locale = 'en';
to = from;
from = 'YYYY-MM-DD';
}
else if (arguments.length === 2) {
locale = 'en';
}
// Order and type get a number value from Moment, everything else
// sees the rendered value
return m.format(type === 'sort' || type === 'type' ? 'x' : to);
};
};
3. You start with loading references to jQuery and Moment.js to let TypeScript know what the corresponding variables refer to. Next, you define the plug-in function. Usually in
TypeScript you use the arrow notation for functions ( => ). In this case, however, because you need access to the arguments property, you have to use the regular function definition.
To prevent tslint from reporting a warning about not using the arrow notation, you can explicitly disable the no-function-expression rule around the function definition.
4. To confirm that everything is working as expected, in the command line, execute:
5. Navigate to the hosted Workbench and add the web part to the canvas. Although visually nothing has changed, the new code base uses TypeScript and its type definitions to help you
maintain the solution.
Migrate jQuery and FullCalendar solution built using Script Editor web part to SharePoint
Framework
5/3/2018 • 24 minutes to read Edit Online
When building SharePoint solutions, SharePoint developers often use the FullCalendar jQuery plug-in to display data in calendar view. FullCalendar is a great alternative to the standard
SharePoint calendar view, as it allows you to render as calendar data from multiple calendar lists, data from non-calendar lists, or even data from outside SharePoint. This article illustrates
how you would migrate a SharePoint customization by using FullCalendar built with the Script Editor web part to the SharePoint Framework.
List of tasks displayed as a calendar built using the Script Editor web part
To illustrate the process of migrating a SharePoint customization using FullCalendar to the SharePoint Framework, you will use the following solution that shows a calendar view of tasks
retrieved from a SharePoint list.
The solution is built using the standard SharePoint Script Editor web part. Following is the code used by the customization.
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.js"></script>
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.css" />
<div id="calendar"></div>
<script>
var PATH_TO_DISPFORM = _spPageContextInfo.webAbsoluteUrl + "/Lists/Tasks/DispForm.aspx";
var TASK_LIST = "Tasks";
var COLORS = ['#466365', '#B49A67', '#93B7BE', '#E07A5F', '#849483', '#084C61', '#DB3A34'];
displayTasks();
function displayTasks() {
$('#calendar').fullCalendar('destroy');
$('#calendar').fullCalendar({
weekends: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
displayEventTime: false,
// open up the display form when a user clicks on an event
eventClick: function (calEvent, jsEvent, view) {
eventClick: function (calEvent, jsEvent, view) {
window.location = PATH_TO_DISPFORM + "?ID=" + calEvent.id;
},
editable: true,
timezone: "UTC",
droppable: true, // this allows things to be dropped onto the calendar
// update the end date when a user drags and drops an event
eventDrop: function (event, delta, revertFunc) {
updateTask(event.id, event.start, event.end);
},
// put the events on the calendar
events: function (start, end, timezone, callback) {
var startDate = start.format('YYYY-MM-DD');
var endDate = end.format('YYYY-MM-DD');
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + restQuery,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=nometadata"
}
})
.done(function (data, textStatus, jqXHR) {
var personColors = {};
var colorNo = 0;
return {
title: task.Title + " - " + assignedTo,
id: task.ID,
color: color, // specify the background color and border color can also create a class and use className parameter.
start: moment.utc(task.StartDate).add("1", "days"),
end: moment.utc(task.DueDate).add("1", "days") // add one day to end date so that calendar properly shows event ending on that day
};
});
callback(events);
});
}
});
}
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + '/_api/contextinfo',
type: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
})
.then(function (data, textStatus, jqXHR) {
return $.ajax({
url: _spPageContextInfo.webAbsoluteUrl +
"/_api/Web/Lists/getByTitle('" + TASK_LIST + "')/Items(" + id + ")",
type: 'POST',
data: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"X-RequestDigest": data.FormDigestValue,
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
});
})
.done(function (data, textStatus, jqXHR) {
alert("Update Successful");
})
.fail(function (jqXHR, textStatus, errorThrown) {
alert("Update Failed");
})
.always(function () {
displayTasks();
});
}
</script>
</script>
NOTE
This solution is based on the work of Mark Rackley, Office Servers and Services MVP and Chief Strategy Officer at PAIT Group. For more information about the original solution, see Using
FullCalendar.io to Create Custom Calendars in SharePoint.
First, the customization loads the libraries it uses: jQuery, Moment.js, and FullCalendar (lines 1-4).
Next, it defines the div into which the generated calendar view is injected (line 5).
It then defines two functions: displayTasks, used to display tasks in the calendar view, and updateTask, which is triggered after dragging and dropping a task to a different date and which
updates the dates on the underlying list item. Each function defines its own REST query, which is then used to communicate with the SharePoint List REST API to retrieve or update list
items.
Using the FullCalendar jQuery plug-in, with little effort users get rich solutions capable of things such as using different colors to mark different events or using drag and drop to reorganize
events.
Migrate the Tasks calendar solution from the Script Editor web part to the SharePoint Framework
NOTE
Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.
Transforming a Script Editor web part-based customization to the SharePoint Framework offers a number of benefits such as more user-friendly configuration and centralized management
of the solution. Following is a step-by-step description of how you would migrate the solution to the SharePoint Framework.
First, you migrate the solution to the SharePoint Framework with as few changes to the original code as possible. Later, you transform the solution's code to TypeScript to benefit from its
development-time type safety features, and replace some of the code with the SharePoint Framework API to fully benefit from its capabilities and simplify the solution even further.
NOTE
The source code of the project in the different stages of migration is available at Tutorial: Migrate jQuery and FullCalendar solution built using Script Editor web part to SharePoint
Framework.
md fullcalendar-taskscalendar
3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:
yo @microsoft/sharepoint
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:
npm shrinkwrap
6. Open your project folder in your code editor. In this tutorial, you will use Visual Studio Code.
{
"externals": {
"jquery": "https://code.jquery.com/jquery-1.11.1.min.js",
"moment": "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js",
"fullcalendar": "https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.js"
}
}
2. Open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file, and after the last import statement, add:
import 'jquery';
import 'moment';
import 'fullcalendar';
displayTasks();
function displayTasks() {
$('#calendar').fullCalendar('destroy');
$('#calendar').fullCalendar({
weekends: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
displayEventTime: false,
// open up the display form when a user clicks on an event
eventClick: function (calEvent, jsEvent, view) {
window.location = PATH_TO_DISPFORM + "?ID=" + calEvent.id;
},
editable: true,
timezone: "UTC",
droppable: true, // this allows things to be dropped onto the calendar
// update the end date when a user drags and drops an event
eventDrop: function (event, delta, revertFunc) {
updateTask(event.id, event.start, event.end);
},
// put the events on the calendar
events: function (start, end, timezone, callback) {
var startDate = start.format('YYYY-MM-DD');
var endDate = end.format('YYYY-MM-DD');
$.ajax({
url: window.webAbsoluteUrl + restQuery,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=nometadata"
}
})
.done(function (data, textStatus, jqXHR) {
var personColors = {};
var colorNo = 0;
return {
title: task.Title + " - " + assignedTo,
id: task.ID,
color: color, // specify the background color and border color can also create a class and use className parameter.
start: moment.utc(task.StartDate).add("1", "days"),
end: moment.utc(task.DueDate).add("1", "days") // add one day to end date so that calendar properly shows event ending on that day
};
});
callback(events);
});
}
});
}
$.ajax({
url: window.webAbsoluteUrl + '/_api/contextinfo',
type: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
})
.then(function (data, textStatus, jqXHR) {
return $.ajax({
url: window.webAbsoluteUrl +
"/_api/Web/Lists/getByTitle('" + TASK_LIST + "')/Items(" + id + ")",
type: 'POST',
data: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"X-RequestDigest": data.FormDigestValue,
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
});
})
.done(function (data, textStatus, jqXHR) {
alert("Update Successful");
})
.fail(function (jqXHR, textStatus, errorThrown) {
alert("Update Failed");
})
.always(function () {
displayTasks();
});
}
This code is almost identical to the original code of the Script Editor web part customization. The only difference is that where the original code retrieved the URL of the current web
from the global _spPageContextInfo variable set by SharePoint (lines 8, 45, 96 and 104), the code in the SharePoint Framework uses a custom variable that you have to set in the
web part.
SharePoint Framework client-side web parts can be used both on classic and modern pages. While the _spPageContextInfo variable is present on classic pages, it's not available on
modern pages, which is why you can't rely on it and need a custom property that you can control yourself instead.
2. To reference this file in the web part, in the code editor, open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file, and change the render method to:
3. Verify that the web part is working as expected by executing the following in the command line:
Because the web part loads its data from SharePoint, you have to test the web part by using the hosted SharePoint Framework workbench.
4. Navigate to https://yourtenant.sharepoint.com/_layouts/workbench.aspx and add the web part to the canvas. You should now see the tasks displayed in a calendar view by using the
FullCalendar jQuery plug-in.
Add support for configuring the web part through web part properties
In the previous steps, you migrated the Tasks calendar solutions from the Script Editor web part to the SharePoint Framework. While the solution already works as expected, it doesn't use
any of the SharePoint Framework benefits. The name of the list from which tasks are loaded is included in the code, and the code itself is plain JavaScript, which is harder to refactor than
TypeScript.
The following steps illustrate how to extend the existing solution to allow users to specify the name of the list to load the data from. Later, you transform the code to TypeScript to benefit
from its type safety features.
Define web part property for storing the name of the list
1. Define a web part property to store the name of the list from which tasks should be loaded. In the code editor, open the
./src/webparts/tasksCalendar/TasksCalendarWebPart.manifest.json file, and rename the default description property to listName and clear its value.
2. Update the web part properties interface to reflect the changes in the manifest. In the code editor, open the ./src/webparts/tasksCalendar/ITasksCalendarWebPartProps.ts file,
and change its contents to:
3. Update the display labels for the listName property. Open the ./src/webparts/tasksCalendar/loc/mystrings.d.ts file, and change its contents to:
define([], function() {
return {
"PropertyPaneDescription": "Tasks calendar settings",
"BasicGroupName": "Data",
"ListNameFieldLabel": "List name"
}
});
5. Update the web part to use the newly defined property. In the code editor, open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file, and change the
getPropertyPaneConfiguration method to:
export default class TasksCalendarWebPart extends BaseClientSideWebPart<ITasksCalendarWebPartProps> {
// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('listName', {
label: strings.ListNameFieldLabel
})
]
}
]
}
]
};
}
To prevent the web part from reloading as users type the name of the list, you've also configured the web part to use the non-reactive property pane by adding the
disableReactivePropertyChanges method and setting its return value to true.
Use the configured name of the list to load the data from
Initially, the name of the list from which the data should be loaded was embedded in the REST queries. Now that users can configure this name, the configured value should be injected into
the REST queries before executing them. The easiest way to do that is by moving the contents of the script.js file to the main web part file.
1. In the code editor, open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file.
2. Change the import statement to load the required libraries to:
import 'fullcalendar';
Because Moment.js is referenced in the code that you will be using later, its name must be known to TypeScript or building the project will fail. The same applies to jQuery. Because
FullCalendar is a jQuery plug-in that attaches itself to the jQuery object, it can be imported the same way as previously.
The last part includes copying the list of colors to use for marking the different events.
3. Copy the displayTasks and updateTask functions from the script.js file, and paste them as follows inside the TasksCalendarWebPart class:
private displayTasks() {
$('#calendar').fullCalendar('destroy');
$('#calendar').fullCalendar({
weekends: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
displayEventTime: false,
// open up the display form when a user clicks on an event
eventClick: (calEvent, jsEvent, view) => {
(window as any).location = this.context.pageContext.web.absoluteUrl +
"/Lists/" + escape(this.properties.listName) + "/DispForm.aspx?ID=" + calEvent.id;
},
editable: true,
timezone: "UTC",
droppable: true, // this allows things to be dropped onto the calendar
// update the end date when a user drags and drops an event
eventDrop: (event, delta, revertFunc) => {
this.updateTask(event.id, event.start, event.end);
},
// put the events on the calendar
events: (start, end, timezone, callback) => {
var startDate = start.format('YYYY-MM-DD');
var endDate = end.format('YYYY-MM-DD');
$.ajax({
url: this.context.pageContext.web.absoluteUrl + restQuery,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=nometadata"
}
})
.done((data, textStatus, jqXHR) => {
var personColors = {};
var colorNo = 0;
var events = data.value.map((task) => {
var assignedTo = task.AssignedTo.map((person) => {
return person.Title;
}).join(', ');
return {
title: task.Title + " - " + assignedTo,
id: task.ID,
color: color, // specify the background color and border color can also create a class and use className parameter.
start: moment.utc(task.StartDate).add("1", "days"),
end: moment.utc(task.DueDate).add("1", "days") // add one day to end date so that calendar properly shows event ending on that day
};
});
callback(events);
});
}
});
}
$.ajax({
url: this.context.pageContext.web.absoluteUrl + '/_api/contextinfo',
type: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
})
.then((data, textStatus, jqXHR) => {
return $.ajax({
url: this.context.pageContext.web.absoluteUrl +
"/_api/Web/Lists/getByTitle('" + escape(this.properties.listName) + "')/Items(" + id + ")",
type: 'POST',
data: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"X-RequestDigest": data.FormDigestValue,
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
});
})
.done((data, textStatus, jqXHR) => {
alert("Update Successful");
})
.fail((jqXHR, textStatus, errorThrown) => {
alert("Update Failed");
})
.always(() => {
this.displayTasks();
});
}
// ...
}
There are a few changes in the code compared to the previous situation. Plain JavaScript functions are now changed into TypeScript methods by replacing the function keyword with
the private modifier. This is required to be able to add them to the TaskCalendarWebPart class. Because both methods are now in the same file as the web part, instead of defining a
global variable to hold the URL of the current site, you can access it directly from the web part context by using the this.context.pageContext.web.absoluteUrl property. Additionally, in
all REST queries, the fixed list name is replaced with the value of the listName property, which holds the name of the list as configured by the user. Before using the value, it's being
escaped by using the lodash's escape function to disallow script injection.
4. As the last step, change the render method to call the newly added displayTasks method:
export default class TasksCalendarWebPart extends BaseClientSideWebPart<ITasksCalendarWebPartProps> {
public render(): void {
this.domElement.innerHTML = `
<div class="${styles.tasksCalendar}">
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.css" />
<div id="calendar"></div>
</div>`;
this.displayTasks();
}
// ...
}
5. Because you have just moved the contents of the script.js file into the main web part file, the script.js is no longer necessary and you can delete it from the project.
6. To verify that the web part is working as expected, run the following in the command line:
7. Navigate to the hosted Workbench and add the web part to the canvas. Open the web part property pane, specify the name of the list with tasks, and select the Apply button to
confirm the changes. You should now see tasks displayed in a calendar view in the web part.
Type definitions for Moment.js are distributed together with the Moment.js package. Even though you're loading Moment.js from a URL, to use its typings, you still need to install the
Moment.js package in the project.
2. Install the Moment.js package by executing the following in the command line:
interface ITask {
ID: number;
Title: string;
StartDate: string;
DueDate: string;
AssignedTo: [{ Title: string }];
}
2. In the web part class, change the displayTasks and updateTask methods to:
// ...
$.ajax({
url: this.context.pageContext.web.absoluteUrl + restQuery,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=nometadata"
}
})
.done((data: { value: ITask[] }, textStatus: string, jqXHR: JQueryXHR): void => {
let personColors: { [person: string]: string; } = {};
let colorNo: number = 0;
return {
title: `${task.Title} - ${assignedTo}`,
id: task.ID,
// specify the background color and border color can also create a class and use className parameter
color: color,
start: moment.utc(task.StartDate).add("1", "days"),
// add one day to end date so that calendar properly shows event ending on that day
end: moment.utc(task.DueDate).add("1", "days")
};
});
callback(events);
});
});
}
});
}
$.ajax({
url: this.context.pageContext.web.absoluteUrl + '/_api/contextinfo',
type: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
})
.then((data: { FormDigestValue: string }, textStatus: string, jqXHR: JQueryXHR): JQueryXHR => {
return $.ajax({
url: `${this.context.pageContext.web.absoluteUrl}\
/_api/Web/Lists/getByTitle('${escape(this.properties.listName)}')/Items(${id})`,
type: 'POST',
data: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"X-RequestDigest": data.FormDigestValue,
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
});
})
.done((data: {}, textStatus: string, jqXHR: JQueryXHR): void => {
alert("Update Successful");
})
.fail((jqXHR: JQueryXHR, textStatus: string, errorThrown: string): void => {
alert("Update Failed");
})
.always((): void => {
this.displayTasks();
});
}
// ...
}
The first and most obvious change when transforming plain JavaScript to TypeScript are explicit types. While they are not required, they make it clear which type of data is expected
where. Any deviation from the specified contract is immediately caught by TypeScript, helping you find possible issues as soon as possible during the development process. This is
particularly useful when working with AJAX responses and their data.
Another change that you might have noticed already is the TypeScript string interpolation. Using string interpolation simplifies dynamic string composition and increases the
readability of your code.
Compare plain JavaScript:
to:
The additional benefit of using TypeScript string interpolation is that you don't need to escape quotes, which also simplifies composing REST queries.
3. To confirm that everything is working as expected, execute the following in the command line:
4. Go to the hosted Workbench and add the web part to the canvas. Although visually nothing has changed, the new code base uses TypeScript and its type definitions to help you
maintain the solution.
Because you want to update a list item, you need to provide SharePoint with a valid request digest token. While it's available on classic pages, it's valid for 3 minutes, so it's always the safest
to retrieve a valid token yourself before performing an update operation. After you obtain the request digest, you have to add it to request headers of the update request. If you don't, the
request fails.
SharePoint Framework SPHttpClient simplifies communicating with SharePoint because it automatically detects if the request is a POST request and needs a valid request digest. If it does,
the SPHttpClient automatically retrieves it from SharePoint and adds it to the request. By comparison, the same request issued using the SPHttpClient would look like this:
this.context.spHttpClient.post(`${this.context.pageContext.web.absoluteUrl}\
/_api/Web/Lists/getByTitle('${escape(this.properties.listName)}')/Items(${id})`, SPHttpClient.configurations.v1, {
body: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
})
.then((response: SPHttpClientResponse): void => {
// ...
});
1. To replace the original jQuery AJAX calls with the SharePoint Framework SPHttpClient API, in the code editor open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts
file. To the list of imports add:
2. In the TasksCalendarWebPart class, replace the displayTasks and updateTask methods with the following code:
return {
title: `${task.Title} - ${assignedTo}`,
id: task.ID,
// specify the background color and border color can also create a class and use className paramter
color: color,
start: moment.utc(task.StartDate).add("1", "days"),
// add one day to end date so that calendar properly shows event ending on that day
end: moment.utc(task.DueDate).add("1", "days")
};
});
callback(events);
});
}
});
}
this.context.spHttpClient.post(`${this.context.pageContext.web.absoluteUrl}\
/_api/Web/Lists/getByTitle('${escape(this.properties.listName)}')/Items(${id})`, SPHttpClient.configurations.v1, {
body: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
})
.then((response: SPHttpClientResponse): void => {
if (response.ok) {
alert("Update Successful");
}
else {
alert("Update Failed");
}
this.displayTasks();
});
}
// ...
}
IM P O R T A N T
If you're suppressing metadata in the responses of the SharePoint REST API, when using the SharePoint Framework SPHttpClient you have to ensure that you're using
application/json;odata.metadata=none and not application/json;odata=nometadata as the value of the Accept header. SPHttpClient uses OData 4.0 and requires the first value. If you
use the latter instead, the request fails with a 406 Not Acceptable response.
3. To confirm that everything is working as expected, execute the following in the command line:
4. Go to the hosted Workbench and add the web part to the canvas. Although there are still no visual changes, the new code uses the SharePoint Framework SPHttpClient, which
simplifies your code and maintains your solution.
Migrate AngularJS applications to SharePoint Framework
3/26/2018 • 19 minutes to read Edit Online
Many organizations have been using AngularJS for building SharePoint solutions in the past. This article shows how to migrate an existing AngularJS application styled using
ngOfficeUIFabric - AngularJS directives for Office UI Fabric, to a SharePoint Framework client-side web part. The sample application used for this tutorial manages To Do items stored in a
SharePoint list.
Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.
Set up project
Before you start migrating your AngularJS application, create and set up a new SharePoint Framework project to host the AngularJS application.
md angular-todo
cd angular-todo
3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:
yo @microsoft/sharepoint
npm shrinkwrap
6. Open your project folder in your code editor. In this tutorial, you will use Visual Studio Code.
"angular": {
"path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.6/angular.min.js",
"globalName": "angular"
},
"ng-office-ui-fabric": "https://cdnjs.cloudflare.com/ajax/libs/ngOfficeUiFabric/0.12.3/ngOfficeUiFabric.js"
Not started
In progress
Completed
this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="homeController as vm">
<div class="${styles.loading}" ng-show="vm.isLoading">
<uif-spinner>Loading...</uif-spinner>
</div>
<div class="entryform" ng-show="vm.isLoading === false">
<uif-textfield uif-label="New to do:" uif-underlined ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)"></uif-textfield>
</div>
<uif-list class="items" ng-show="vm.isLoading === false" >
<uif-list-item ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'done': todo.done}">
<uif-list-item-primary-text>{{todo.title}}</uif-list-item-primary-text>
<uif-list-item-actions>
<uif-list-item-action ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<uif-icon uif-type="check"></uif-icon>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<uif-icon uif-type="reactivate"></uif-icon>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.deleteTodo(todo)">
<uif-icon uif-type="trash"></uif-icon>
</uif-list-item-action>
</uif-list-item-actions>
</uif-list-item>
</uif-list>
</div>
</div>`;
angular.bootstrap(this.domElement, ['todoapp']);
}
}
// ...
}
.toDo {
.loading {
margin: 0 auto;
width: 6em;
}
}
gulp trust-dev-cert
2. To the URL of your SharePoint site, add /_layouts/workbench.aspx , for example, https://contoso.sharepoint.com/_layouts/workbench.aspx , and navigate to it in the web browser.
If you followed all steps correctly, you should see the web part in the browser showing the form to add To Do items.
3. Add a few To Do items to verify that the web part is working as expected.
.toDo {
.loading {
margin: 0 auto;
width: 6em;
}
ul, li {
margin: 0;
padding: 0;
}
:global {
.ms-Spinner{position:relative;height:20px}.ms-Spinner.ms-Spinner--large{height:28px}.ms-Spinner.ms-Spinner--large .ms-Spinner-label{left:34px;top:6px}.ms-Spinner-circle{position:absolute;b
.ms-TextField{color:#333;font-family:Segoe UI Regular WestEuropean,Segoe UI,Tahoma,Arial,sans-serif;font-size:14px;font-weight:400;box-sizing:border-box;margin:0;padding:0;box-shadow:none;
.ms-Label{margin:0;padding:0;box-shadow:none;box-sizing:border-box;display:block;padding:5px 0}.ms-Label.is-required:after{content:' *';color:#a80000}.ms-Label.is-disabled{color:#a6a6a6}@m
.ms-ListItem{font-family:"Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;font-size:14px;font-weigh
}
}
2. In the ./src/webparts/toDo/ToDoWebPart.ts file, in the render method, change the application rendering template to use new Office UI Fabric icons.
export default class ToDoWebPart extends BaseClientSideWebPart<IToDoWebPartProps> {
// ...
public render(): void {
if (this.renderedOnce === false) {
require('./app/app.module');
require('./app/app.config');
require('./app/data.service');
require('./app/home.controller');
this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="homeController as vm">
<div class="${styles.loading}" ng-show="vm.isLoading">
<uif-spinner>Loading...</uif-spinner>
</div>
<div id="entryform" ng-show="vm.isLoading === false">
<uif-textfield uif-label="New to do:" uif-underlined ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)"></uif-textfield>
</div>
<uif-list id="items" ng-show="vm.isLoading === false" >
<uif-list-item ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'${styles.done}': todo.done}">
<uif-list-item-primary-text>{{todo.title}}</uif-list-item-primary-text>
<uif-list-item-actions>
<uif-list-item-action ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<i class="ms-Icon ms-Icon--CheckMark" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<i class="ms-Icon ms-Icon--RevToggleKey" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.deleteTodo(todo)">
<i class="ms-Icon ms-Icon--Delete" aria-hidden="true"></i>
</uif-list-item-action>
</uif-list-item-actions>
</uif-list-item>
</uif-list>
</div>
</div>`;
angular.bootstrap(this.domElement, ['todoapp']);
}
}
// ...
}
If you refresh the web part in the web browser, you see that it is now correctly styled.
interface ITodoItem {
Id: number;
Title: string;
Status: string;
}
this.$http({
url: url,
method: 'GET',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ value: ITodoItem[] }>): void => {
const todos: ITodo[] = [];
for (let i: number = 0; i < result.data.value.length; i++) {
const todo: ITodoItem = result.data.value[i];
todos.push({
id: todo.Id,
title: todo.Title,
done: todo.Status === 'Completed'
});
}
deferred.resolve(todos);
});
return deferred.promise;
}
return deferred.promise;
}
this.getRequestDigest()
.then((requestDigest: string): void => {
this.$http({
url: `${this.sharepointApi}web/lists/getbytitle('${this.todoListName}')/items(${todo.id})`,
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata',
'X-RequestDigest': requestDigest,
'IF-MATCH': '*',
'X-HTTP-Method': 'DELETE'
'X-HTTP-Method': 'DELETE'
}
}).then((result: angular.IHttpPromiseCallbackArg<{}>): void => {
deferred.resolve();
});
});
return deferred.promise;
}
return deferred.promise;
}
this.$http({
url: this.sharepointApi + 'contextinfo',
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ FormDigestValue: string }>): void => {
deferred.resolve(result.data.FormDigestValue);
}, (err: any): void => {
deferred.reject(err);
});
return deferred.promise;
}
this.$http({
url: `${this.sharepointApi}web/lists/getbytitle('${this.todoListName}')?$select=ListItemEntityTypeFullName`,
method: 'GET',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ ListItemEntityTypeFullName: string }>): void => {
deferred.resolve(result.data.ListItemEntityTypeFullName);
}, (err: any): void => {
deferred.reject(err);
});
return deferred.promise;
}
}
this.dataService.addTodo(this.newItem)
.then((): void => {
this.newItem = null;
this.dataService.getTodos()
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
}
this.dataService.deleteTodo(todo)
.then((): void => {
this.dataService.getTodos()
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
}
this.dataService.setTodoStatus(todo, true)
.then((): void => {
this.dataService.getTodos()
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
this.dataService.setTodoStatus(todo, false)
.then((): void => {
this.dataService.getTodos()
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
}
import 'ng-office-ui-fabric';
config();
todoapp
.controller('HomeController', HomeController)
.service('DataService', DataService);
this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="HomeController as vm">
<div class="${styles.loading}" ng-show="vm.isLoading">
<uif-spinner>Loading...</uif-spinner>
</div>
<div id="entryform" ng-show="vm.isLoading === false">
<uif-textfield uif-label="New to do:" uif-underlined ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)"></uif-textfield>
</div>
<uif-list id="items" ng-show="vm.isLoading === false" >
<uif-list-item ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'${styles.done}': todo.done}">
<uif-list-item-primary-text>{{todo.title}}</uif-list-item-primary-text>
<uif-list-item-actions>
<uif-list-item-action ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<i class="ms-Icon ms-Icon--CheckMark" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<i class="ms-Icon ms-Icon--RevToggleKey" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.deleteTodo(todo)">
<i class="ms-Icon ms-Icon--Delete" aria-hidden="true"></i>
</uif-list-item-action>
</uif-list-item-actions>
</uif-list-item>
</uif-list>
</div>
</div>`;
angular.bootstrap(this.domElement, ['todoapp']);
}
}
// ...
}
2. To verify that the upgrade to TypeScript has been successful, in the command line, run:
3. In the web browser, refresh the SharePoint Workbench, which should display your web part as previously.
Even though the way the web part works hasn't changed, your code is improved. In case of a future update, you can more easily verify the correctness and integrity of your code already
during development.
"properties": {
"todoListName": "Todo",
"hideFinishedTasks": false
}
2. In the ./src/webparts/toDo/ToDoWebPart.ts file, change the definition of the IToDoWebPartProps interface to:
import {
BaseClientSideWebPart,
IPropertyPaneSettings,
PropertyPaneTextField,
PropertyPaneToggle
} from '@microsoft/sp-webpart-base';
5. Add the missing resource strings by changing the ./src/webparts/toDo/loc/mystrings.d.ts file contents to:
declare interface IToDoWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
ListNameFieldLabel: string;
HideFinishedTasksFieldLabel: string;
}
6. In the ./src/webparts/toDo/loc/en-us.js file, add translations for the newly added strings:
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListNameFieldLabel": "List name",
"HideFinishedTasksFieldLabel": "Hide finished tasks"
}
});
import 'ng-office-ui-fabric';
todoapp
.controller('HomeController', HomeController)
.service('DataService', DataService);
interface ITodoItem {
Id: number;
Title: string;
Status: string;
}
this.$http({
url: url,
method: 'GET',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ value: ITodoItem[] }>): void => {
const todos: ITodo[] = [];
for (let i: number = 0; i < result.data.value.length; i++) {
const todo: ITodoItem = result.data.value[i];
todos.push({
id: todo.Id,
title: todo.Title,
done: todo.Status === 'Completed'
});
}
deferred.resolve(todos);
});
return deferred.promise;
}
return deferred.promise;
}
this.getRequestDigest(sharePointApi)
.then((requestDigest: string): void => {
this.$http({
url: `${sharePointApi}web/lists/getbytitle('${todoListName}')/items(${todo.id})`,
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata',
'X-RequestDigest': requestDigest,
'IF-MATCH': '*',
'X-HTTP-Method': 'DELETE'
}
}).then((result: angular.IHttpPromiseCallbackArg<{}>): void => {
deferred.resolve();
});
});
return deferred.promise;
}
public setTodoStatus(todo: ITodo, done: boolean, sharePointApi: string, todoListName: string): angular.IPromise<{}> {
const deferred: angular.IDeferred<{}> = this.$q.defer();
return deferred.promise;
}
this.$http({
url: sharePointApi + 'contextinfo',
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ FormDigestValue: string }>): void => {
deferred.resolve(result.data.FormDigestValue);
}, (err: any): void => {
deferred.reject(err);
});
return deferred.promise;
}
this.$http({
url: `${sharePointApi}web/lists/getbytitle('${todoListName}')?$select=ListItemEntityTypeFullName`,
method: 'GET',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ ListItemEntityTypeFullName: string }>): void => {
deferred.resolve(result.data.ListItemEntityTypeFullName);
}, (err: any): void => {
deferred.reject(err);
});
return deferred.promise;
}
}
this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="HomeController as vm">
<div class="${styles.configurationNeeded}" ng-show="vm.configurationNeeded">
Please configure the web part
</div>
<div ng-show="vm.configurationNeeded === false">
<div id="loading" ng-show="vm.isLoading">
<uif-spinner>Loading...</uif-spinner>
</div>
<div id="entryform" ng-show="vm.isLoading === false">
<uif-textfield uif-label="New to do:" uif-underlined ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)"></uif-textfield>
</div>
<uif-list id="items" ng-show="vm.isLoading === false" >
<uif-list-item ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'${styles.done}': todo.done}">
<uif-list-item-primary-text>{{todo.title}}</uif-list-item-primary-text>
<uif-list-item-actions>
<uif-list-item-action ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<i class="ms-Icon ms-Icon--CheckMark" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<i class="ms-Icon ms-Icon--RevToggleKey" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.deleteTodo(todo)">
<i class="ms-Icon ms-Icon--Delete" aria-hidden="true"></i>
</uif-list-item-action>
</uif-list-item-actions>
</uif-list-item>
</uif-list>
</div>
</div>
</div>`;
this.$injector.get('$rootScope').$broadcast('configurationChanged', {
sharePointApi: this.context.pageContext.web.absoluteUrl + '/_api/',
todoListName: this.properties.todoListName,
hideFinishedTasks: this.properties.hideFinishedTasks
});
}
// ...
}
3. In the ./src/webparts/toDo/ToDoWebPart.module.scss file, add the missing styles for the .configurationNeeded class:
.toDo {
/* ... */
.configurationNeeded {
margin: 0 auto;
width: 100%;
text-align: center;
}
/* ... */
}
2. Extend the constructor of the HomeController class with injecting the root scope service, and change its contents to:
$rootScope.$on('configurationChanged',
(event: angular.IAngularEvent,
args: {
sharePointApi: string;
todoListName: string;
hideFinishedTasks: boolean;
}): void => {
vm.init(args.sharePointApi, args.todoListName, args.hideFinishedTasks);
});
}
// ...
}
4. Update all remaining methods in the HomeController class to use the configuration values from the class properties:
export default class HomeController {
// ...
private loadTodos(): void {
this.isLoading = true;
this.dataService.getTodos(this.sharePointApi, this.todoListName, this.hideFinishedTasks)
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
})
.finally((): void => {
this.isLoading = false;
});
}
5. Verify that the web part is working correctly by executing the following in the command line:
6. In your web browser, go to the SharePoint Workbench and add the web part to canvas. If you toggle the Hide finished tasks option, you should see completed tasks being displayed
or hidden accordingly.
Work with __REQUESTDIGEST
3/26/2018 • 3 minutes to read Edit Online
When executing non-GET REST requests to the SharePoint API, you must add a valid request digest to your request. This digest proves validity of your request to SharePoint. Because this
token is valid only for a limited period of time, you have to ensure that the token you have is valid before adding it to your request or the request fails.
In classic pages, SharePoint includes a request digest token on the page in a hidden field named __REQUESTDIGEST. One of the most common approaches to work with the request digest
is to obtain it from that field and add it to the request, for example:
Such a request would work initially, but if the user has the page open for a longer period of time, the request digest on the page expires and the request fails with a 403 FORBIDDEN result.
By default, a request digest token is valid for 30 minutes, so before using it, you have to ensure that it's still valid. In the past you had to do this manually, by comparing the timestamp from
the request digest with the current time.
SharePoint Framework simplifies this process by offering you two ways of ensuring that your request has a valid request digest token.
// ...
import { IDigestCache, DigestCache } from '@microsoft/sp-http';
2. Whenever you need a valid request digest token, retrieve a reference to the DigestCache service, and call its fetchDigest method:
// ...
import { IDigestCache, DigestCache } from '@microsoft/sp-http';
// ...
}
See also
SharePoint Framework Overview
Connect to SharePoint using the JavaScript Object Model (JSOM)
5/3/2018 • 14 minutes to read Edit Online
In the past, when building SharePoint customizations, you might have used the SharePoint JavaScript Object Model (JSOM) to communicate with SharePoint. This is no longer the
recommended path (see Considerations later in this article), but there are still valid use cases such as code migration.
To use SharePoint JSOM in your SharePoint Framework component, you must first reference it. In the past it was already available on the page for you to use. In the SharePoint Framework,
it has to be explicitly loaded.
There are two ways to reference SharePoint JSOM in the SharePoint Framework:
Declarative - through configuration
Imperative - through code
Each of these approaches has advantages and disadvantages, and it's important for you to understand each of them.
NOTE
Before following the steps in this article, be sure to set up your SharePoint Framework development environment.
md react-sharepointlists
cd react-sharepointlists
3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:
yo @microsoft/sharepoint
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:
npm shrinkwrap
6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor you prefer.
7. To open the directory in Visual Studio Code, from the console enter:
code .
{
// ...
"externals": {
"sp-init": {
"path": "https://contoso.sharepoint.com/_layouts/15/init.js",
"globalName": "$_global_init"
},
"microsoft-ajax": {
"path": "https://contoso.sharepoint.com/_layouts/15/MicrosoftAjax.js",
"globalName": "Sys",
"globalDependencies": [
"sp-init"
]
},
"sp-runtime": {
"path": "https://contoso.sharepoint.com/_layouts/15/SP.Runtime.js",
"globalName": "SP",
"globalDependencies": [
"microsoft-ajax"
]
},
"sharepoint": {
"path": "https://contoso.sharepoint.com/_layouts/15/SP.js",
"globalName": "SP",
"globalDependencies": [
"sp-runtime"
]
}
}
// ...
}
Each of the entries points to different script files that together allow you to use SharePoint JSOM in your SPFx component. All of these scripts are distributed as non-module scripts.
This is why each registration entry requires a URL, (specified using the path property) and the name used by the script (provided in the globalName property). To ensure that these
scripts load in the right order, the dependencies between these scripts are specified by using the globalDependencies property.
Additional scripts may need to be added depending on the JSOM functionality that you are using (e.g. sp.taxonomy.js).
SharePoint JSOM is not distributed as a module, so you cannot import it directly in your code. Instead, you need to register its TypeScript typings globally.
2. In the code editor, open the ./tsconfig.json file, and in the types property, right after the webpack-env entry, add references to microsoft-ajax and sharepoint:
{
"compilerOptions": {
// ...
"types": [
"es6-promise",
"es6-collections",
"webpack-env",
"microsoft-ajax",
"sharepoint"
]
}
}
require('sp-init');
require('microsoft-ajax');
require('sp-runtime');
require('sharepoint');
These names correspond to the external references that you added previously, so SharePoint Framework loads these scripts from the specified URLs.
To demonstrate using SharePoint JSOM for communicating with SharePoint, you need to retrieve and render the titles of all SharePoint lists located in the current site.
2. To pass the URL of the current site into the component, open the ./src/webparts/sharePointLists/SharePointListsWebPart.ts file in the code editor, and change the render
method to:
ReactDom.render(element, this.domElement);
}
// ...
}
this.state = {
listTitles: [],
loadingLists: false,
error: null
};
}
// ...
}
Load information about SharePoint lists from the current site using JSOM
The sample client-side web part used in this article loads information about SharePoint lists in the current site after selecting a button.
1. In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file. In the SharePointLists class, add a new method named getListsTitles :
this.state = {
listTitles: [],
loadingLists: false,
error: null
};
this.getListsTitles = this.getListsTitles.bind(this);
}
// ...
2. To ensure the correct scoping of the method, we bind it to the web part in the constructor. In the getListsTitles method, use SharePoint JSOM to load the titles of SharePoint lists in
the current site:
export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {
// ...
private getListsTitles(): void {
this.setState({
loadingLists: true,
listTitles: [],
error: null
});
We start by resetting the component's state to communicate to the user that the component is loading information from SharePoint. Using the URL of the current site passed to the
component through its properties, we instantiate a new SharePoint context. Using SharePoint JSOM, we load lists from the current site. To optimize the request for performance, we specify
that only the Title property should be loaded.
Next, we execute the query by calling the executeQueryAsync method and passing two callback functions. After the query is completed, we enumerate through the collection of retrieved lists,
store their titles in an array, and update the component's state.
return (
<div className={styles.sharePointLists}>
<div className={styles.container}>
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span className="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p className="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.description)}</p>
<a className={styles.button} onClick={this.getListsTitles} role="button">
<span className={styles.label}>Get lists titles</span>
</a><br />
{this.state.loadingLists &&
<span>Loading lists...</span>}
{this.state.error &&
<span>An error has occurred while loading lists: {this.state.error}</span>}
{this.state.error === null && titles &&
<ul>
{titles}
</ul>}
</div>
</div>
</div>
</div>
);
}
// ...
}
2. At this point, you should be able to add your web part to the page and see the titles of SharePoint lists in the current site. To verify that the project is working correctly, run the
following command from the console:
3. As you are using SharePoint JSOM to communicate with SharePoint, you have to test the web part by using the hosted version of the SharePoint Workbench (which is why the
--nobrowser parameter is specified to prevent the automatic loading of the local Workbench).
Referencing SharePoint JSOM scripts declaratively as external scripts is convenient and allows you to keep your code clean. One disadvantage, however, is that it requires specifying absolute
URLs to the location from which SharePoint JSOM scripts should be loaded. If you're using separate SharePoint tenants for development, testing, and production, it requires some additional
work to change these URLs for the different environments accordingly. In such cases, you may consider referencing JSOM imperatively by using the SPComponentLoader to load the scripts
in the SPFx component's code.
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"share-point-lists-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/sharePointLists/SharePointListsWebPart.js",
"manifest": "./src/webparts/sharePointLists/SharePointListsWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"SharePointListsWebPartStrings": "lib/webparts/sharePointLists/loc/{locale}.js"
}
}
With the SharePoint JSOM scripts no longer being registered as external scripts, you cannot reference them directly in your code.
2. In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file, and remove the require statements pointing to the different SharePoint JSOM
scripts.
2. Add the newly added property to the state definitions in the React component. In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file.
Update the constructor to the following code:
this.state = {
listTitles: [],
loadingLists: false,
error: null,
loadingScripts: true
};
this.getListsTitles = this.getListsTitles.bind(this);
}
// ...
}
3. In the same file, update the getListsTitles method to the following code:
4. To communicate the status of loading the SharePoint JSOM scripts to the user, update the render method to the following code:
export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {
// ...
public render(): React.ReactElement<ISharePointListsProps> {
const titles: JSX.Element[] = this.state.listTitles.map((listTitle: string, index: number, listTitles: string[]): JSX.Element => {
return <li key={index}>{listTitle}</li>;
});
return (
<div className={styles.sharePointLists}>
<div className={styles.container}>
{this.state.loadingScripts &&
<div className="ms-Grid" style={{ color: "#666", backgroundColor: "#f4f4f4", padding: "80px 0", alignItems: "center", boxAlign: "center" }}>
<div className="ms-Grid-row" style={{ color: "#333" }}>
<div className="ms-Grid-col ms-u-hiddenSm ms-u-md3"></div>
<div className="ms-Grid-col ms-u-sm12 ms-u-md6" style={{ height: "100%", whiteSpace: "nowrap", textAlign: "center" }}>
<i className="ms-fontSize-su ms-Icon ms-Icon--CustomList" style={{ display: "inline-block", verticalAlign: "middle", whiteSpace: "normal" }}></i><span className="ms-fontWeigh
</div>
<div className="ms-Grid-col ms-u-hiddenSm ms-u-md3"></div>
</div>
<div className="ms-Grid-row" style={{ width: "65%", verticalAlign: "middle", margin: "0 auto", textAlign: "center" }}>
<span style={{ color: "#666", fontSize: "17px", display: "inline-block", margin: "24px 0", fontWeight: 100 }}>Loading SharePoint JSOM scripts...</span>
</div>
<div className="ms-Grid-row"></div>
</div>}
{this.state.loadingScripts === false &&
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span className="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p className="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.description)}</p>
<a className={styles.button} onClick={this.getListsTitles} role="button">
<span className={styles.label}>Get lists titles</span>
</a><br />
{this.state.loadingLists &&
<span>Loading lists...</span>}
{this.state.error &&
<span>An error has occurred while loading lists: {this.state.error}</span>}
{this.state.error === null && titles &&
<ul>
{titles}
</ul>}
</div>
</div>
}
</div>
</div>
);
}
// ...
}
5. When the React component's state indicates that the SharePoint JSOM scripts are being loaded, it displays a placeholder. After the scripts have been loaded, the web part displays the
expected content with the button allowing users to load the information about SharePoint lists in the current site.
2. Using a series of chained promises, we load the different scripts that together enable using SharePoint JSOM in your SharePoint Framework component. Note that by using the
SPComponentLoader , you can use server-relative URLs that load the scripts from the current SharePoint tenant. After all scripts have been loaded, you update the React component's
state confirming that all prerequisites have been loaded and the web part is ready to use.
3. Confirm that the web part is working as expected by running the following command from the console:
Just as before, the web part should show the titles of SharePoint lists in the current site.
While using the SPComponentLoader requires some additional effort, it allows you to use server-relative URLs, which is beneficial in scenarios when you're using different tenants for
development, testing, and production.
Considerations
In the past, when building client-side customizations on SharePoint, you might have used SharePoint JSOM to communicate with SharePoint. However, the recommended approach is to use
the SharePoint REST API either directly or through the PnP JavaScript Core Library.
When SharePoint JSOM was introduced, it was the first step towards supporting client-side solutions on SharePoint. However, it is no longer being actively maintained and might not offer
access to all capabilities available through the REST API. Additionally, whether using the SharePoint REST API directly or through the PnP JavaScript Core Library, you can use promises
which significantly simplify writing asynchronous code (a common problem when utilizing JSOM).
Although there are still a limited number of cases where SharePoint JSOM provides access to data and methods not yet covered by the SharePoint REST API, where possible, the REST API
should be preferred.
If you have existing customizations using SharePoint JSOM and are considering migrating them to the SharePoint Framework, this article should provide you with the necessary
information about using SharePoint JSOM in SharePoint Framework solutions. Longer term, however, you should consider changing how you communicate with SharePoint to either using
the SharePoint REST API directly or through the PnP JavaScript Core Library.
Overview of SharePoint Framework Extensions
3/26/2018 • 2 minutes to read Edit Online
You can use SharePoint Framework (SPFx) Extensions to extend the SharePoint user experience. With SharePoint Framework Extensions, you can customize more facets of the SharePoint
experience, including notification areas, toolbars, and list data views. SharePoint Framework Extensions are available in all Office 365 subscriptions for production usage.
NOTE
You can get an Office 365 developer subscription when you join the Office 365 Developer Program. See the Office 365 Developer Program documentation for step-by-step instructions
about how to join the Office 365 Developer Program and sign up and configure your subscription.
SharePoint Framework Extensions enable you to extend the SharePoint user experience within modern pages and document libraries, while using the familiar SharePoint Framework tools
and libraries for client-side development. Specifically, the SharePoint Framework includes three new extension types:
Application Customizers. Adds scripts to the page, and accesses well-known HTML element placeholders and extends them with custom renderings.
Field Customizers. Provides modified views to data for fields within a list.
Command Sets. Extends the SharePoint command surfaces to add new actions, and provides client-side code that you can use to implement behaviors.
You can build extensions alongside common scripting frameworks, such as AngularJS and React, in addition to plain JavaScript projects. For example, you can use React along with
components from Office UI Fabric React to create experiences based on the same components used in Office 365.
NOTE
There is a known bug with list and library extension support in the classic experiences. These only work currently in context of modern team sites, also known as group associated team sites.
Work is being done to address this issue.
Get started
1. If you haven't installed the SharePoint Framework, follow the steps to Set up your development environment.
2. After you install the SharePoint Framework, run the following command to update your Yeoman templates with the latest version:
3. Next, you can Build your first SharePoint Framework Extension (Hello World part 1).
Stay up to date
To keep track of improvements to the SharePoint Framework, including updates to extensions, see the following:
@SharePoint and @OfficeDev on Twitter
Office Developer Blog
Provide feedback
We invite you to give us your feedback on the SharePoint Framework General Availability release. You can use the following resources to provide feedback directly to the SharePoint
engineering team:
sp-dev-docs repository issue list - Questions, issues, and comments.
SharePoint StackExchange - Tag with #spfx, #spfx-extensions, and #spfx-tooling.
SharePoint Developer - Microsoft Tech Community group.
SharePoint Developer UserVoice - Request new capabilities and features.
See also
Overview of the SharePoint Framework
SharePoint Framework development tools and libraries
Build your first SharePoint Framework Extension (Hello World part 1)
7/9/2018 • 6 minutes to read Edit Online
SharePoint Framework (SPFx) Extensions are client-side components that run inside the context of a SharePoint page. You can deploy extensions to SharePoint Online, and you can use
modern JavaScript tools and libraries to build them.
You can also follow the steps in this article by watching the video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/yrFNu6K7iuU
md app-extension
cd app-extension
yo @microsoft/sharepoint
4. When prompted:
Accept the default app-extension as your solution name, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select Application Customizer as the extension type to be created.
5. The next set of prompts ask for specific information about your extension. When prompted:
Accept the default HelloWorld as your extension name, and select Enter.
Accept the default HelloWorld description as your extension description, and select Enter.
For the next question Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites...., ensure you select No (N) , and select Enter.
If you select Yes (y), the scaffolding will not generate the Elements.xml feature deployment file.
NOTE
If you use a name for the extension that is too long, you might encounter issues. The entries provided are used to generate an alias entry for the Application Customizer
manifest JSON file. If the alias is longer than 40 characters, you get an exception when you try to serve the extension by using gulp serve --nobrowser . You can resolve this by
updating the alias entry afterward.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:
npm shrinkwrap
7. Next, type the following into the console to start Visual Studio Code.
code .
NOTE
Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your extension.
Notice how the default solution structure looks like the solution structure for client-side web parts. This is the basic SharePoint Framework solution structure, with similar
configuration options across all solution types.
The logic for your Application Customizer is contained in the onInit method, which is called when the client-side extension is first activated on the page. This event occurs after this.context
and this.properties are assigned. As with web parts, onInit() returns a promise that you can use to perform asynchronous operations.
NOTE
The class constructor is called at an early stage, when this.context and this.properties are undefined. Custom initiation logic is not supported here.
The following are the contents of onInit() in the default solution. This default solution writes a log to the Dev Dashboard, and then displays a simple JavaScript alert when the page renders.
If your Application Customizer uses the ClientSideComponentProperties JSON input, it is deserialized into the BaseExtension.properties object. You can define an interface to describe
it. The default template is looking for a property called testMessage. If that property is provided, it outputs it in an alert message.
NOTE
If you do not have the SPFx developer certificate installed, Workbench notifies you that it is not configured to load scripts from localhost. If this happens, stop the process that is
currently running in the console window, run the gulp trust-dev-cert command in your project directory console to install the developer certificate, and then run the
gulp serve --nobrowser command again.
You use the --nobrowser option because you don't need to launch the local Workbench since you can't debug extensions locally.
When the code compiles without errors, it serves the resulting manifest from https://localhost:4321.
2. To test your extension, go to a modern list view page in your SharePoint environment and append the following query string parameters to the URL. Notice that you need to update
the ID to match your own extension identifier. This is available in the HelloWorldApplicationCustomizer.manifest.json file.
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":"ClientSideExtension.ApplicationCustomizer","p
contoso.sharepoint.com/Lists/Contoso/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":
Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages
1. Select Load debug scripts to continue loading scripts from your local host.
This dialog is thrown by your SharePoint Framework Extension. Note that because you provided the testMessage property as part of the debug query parameters, it's included in the
alert message. You can configure your extension instances based on the client component properties, which are passed for the instance in runtime mode.
NOTE
If you have issues with debugging, double-check the URL query parameters used for the query. Some browsers encode the parameters and in some scenarios this affects the behavior.
Next steps
Congratulations, you got your first SharePoint Framework Extension running!
To continue building out your extension, see Using page placeholders from Application Customizer (Hello World part 2). You use the same project and take advantage of specific content
placeholders for modifying the UI of SharePoint. Notice that the gulp serve command is still running in your console window (or in Visual Studio Code if you are using the editor). You can
continue to let it run while you go to the next article.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Build your first SharePoint Framework Extension (Hello World part 1)
7/9/2018 • 6 minutes to read Edit Online
SharePoint Framework (SPFx) Extensions are client-side components that run inside the context of a SharePoint page. You can deploy extensions to SharePoint Online, and you can use
modern JavaScript tools and libraries to build them.
You can also follow the steps in this article by watching the video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/yrFNu6K7iuU
md app-extension
cd app-extension
yo @microsoft/sharepoint
4. When prompted:
Accept the default app-extension as your solution name, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select Application Customizer as the extension type to be created.
5. The next set of prompts ask for specific information about your extension. When prompted:
Accept the default HelloWorld as your extension name, and select Enter.
Accept the default HelloWorld description as your extension description, and select Enter.
For the next question Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites...., ensure you select No (N) , and select Enter.
If you select Yes (y), the scaffolding will not generate the Elements.xml feature deployment file.
NOTE
If you use a name for the extension that is too long, you might encounter issues. The entries provided are used to generate an alias entry for the Application Customizer
manifest JSON file. If the alias is longer than 40 characters, you get an exception when you try to serve the extension by using gulp serve --nobrowser . You can resolve this by
updating the alias entry afterward.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:
npm shrinkwrap
7. Next, type the following into the console to start Visual Studio Code.
code .
NOTE
Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your extension.
Notice how the default solution structure looks like the solution structure for client-side web parts. This is the basic SharePoint Framework solution structure, with similar
configuration options across all solution types.
The logic for your Application Customizer is contained in the onInit method, which is called when the client-side extension is first activated on the page. This event occurs after this.context
and this.properties are assigned. As with web parts, onInit() returns a promise that you can use to perform asynchronous operations.
NOTE
The class constructor is called at an early stage, when this.context and this.properties are undefined. Custom initiation logic is not supported here.
The following are the contents of onInit() in the default solution. This default solution writes a log to the Dev Dashboard, and then displays a simple JavaScript alert when the page renders.
If your Application Customizer uses the ClientSideComponentProperties JSON input, it is deserialized into the BaseExtension.properties object. You can define an interface to describe
it. The default template is looking for a property called testMessage. If that property is provided, it outputs it in an alert message.
NOTE
If you do not have the SPFx developer certificate installed, Workbench notifies you that it is not configured to load scripts from localhost. If this happens, stop the process that is
currently running in the console window, run the gulp trust-dev-cert command in your project directory console to install the developer certificate, and then run the
gulp serve --nobrowser command again.
You use the --nobrowser option because you don't need to launch the local Workbench since you can't debug extensions locally.
When the code compiles without errors, it serves the resulting manifest from https://localhost:4321.
2. To test your extension, go to a modern list view page in your SharePoint environment and append the following query string parameters to the URL. Notice that you need to update
the ID to match your own extension identifier. This is available in the HelloWorldApplicationCustomizer.manifest.json file.
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":"ClientSideExtension.ApplicationCustomizer","p
contoso.sharepoint.com/Lists/Contoso/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":
Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages
1. Select Load debug scripts to continue loading scripts from your local host.
This dialog is thrown by your SharePoint Framework Extension. Note that because you provided the testMessage property as part of the debug query parameters, it's included in the
alert message. You can configure your extension instances based on the client component properties, which are passed for the instance in runtime mode.
NOTE
If you have issues with debugging, double-check the URL query parameters used for the query. Some browsers encode the parameters and in some scenarios this affects the behavior.
Next steps
Congratulations, you got your first SharePoint Framework Extension running!
To continue building out your extension, see Using page placeholders from Application Customizer (Hello World part 2). You use the same project and take advantage of specific content
placeholders for modifying the UI of SharePoint. Notice that the gulp serve command is still running in your console window (or in Visual Studio Code if you are using the editor). You can
continue to let it run while you go to the next article.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Use page placeholders from Application Customizer (Hello World part 2)
7/9/2018 • 6 minutes to read Edit Online
Application Customizers provide access to well-known locations on SharePoint pages that you can modify based on your business and functional requirements. For example, you can create
dynamic header and footer experiences that render across all the pages in SharePoint Online.
This model is similar to using a UserCustomAction collection in a Site or Web object to modify the page experience via custom JavaScript. The key difference or advantage with
SharePoint Framework (SPFx) Extensions is that your page elements won't change if changes are made to the HTML/DOM structure in SharePoint Online.
This article describes how to extend your Hello World extension to take advantage of page placeholders.
You can also follow these steps by watching the video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/3LXuYBaJ1Lc
After you get the placeholder object, you have full control over what is presented to the end user.
Notice that you're requesting a well-known placeholder by using the corresponding well-known identifier. In this case, the code is accessing the footer section of the page by using the
Bottom identifier.
Modify the Application Customizer to access and modify placeholders by adding custom HTML elements
1. In Visual Studio Code (or your preferred IDE), open src\extensions\helloWorld\HelloWorldApplicationCustomizer.ts.
2. Add the PlaceholderContent and PlaceholderName to the import from @microsoft/sp-application-base by updating the import statement as follows:
import {
BaseApplicationCustomizer,
PlaceholderContent,
PlaceholderName
} from '@microsoft/sp-application-base';
Also add the following import statements after the strings import at the top of the file:
These are the styles that are used in the HTML output for the header and footer placeholders.
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
.app {
.top {
height:60px;
text-align:center;
line-height:2.5;
font-weight:bold;
display: flex;
align-items: center;
justify-content: center;
background-color: $ms-color-themePrimary;
color: $ms-color-white;
.bottom {
height:40px;
text-align:center;
line-height:2.5;
font-weight:bold;
display: flex;
align-items: center;
justify-content: center;
background-color: $ms-color-themePrimary;
color: $ms-color-white;
}
}
6. In the HelloWorldApplicationCustomizer.ts file, update the IHelloWorldApplicationCustomizerProperties interface to add specific properties for Header and Footer, as
follows.
NOTE
If your Command Set uses the ClientSideComponentProperties JSON input, it is deserialized into the BaseExtension.properties object. You can define an interface to describe it.
7. Add the following private variables inside the HelloWorldApplicationCustomizer class. In this scenario, these can just be local variables in an onRender method, but if you want to
share them with other objects, define them as private variables.
@override
public onInit(): Promise<void> {
Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);
console.log('HelloWorldApplicationCustomizer._renderPlaceHolders()');
console.log('Available placeholders: ',
this.context.placeholderProvider.placeholderNames.map(name => PlaceholderName[name]).join(', '));
// The extension should not assume that the expected placeholder is available.
if (!this._topPlaceholder) {
console.error('The expected placeholder (Top) was not found.');
return;
}
if (this.properties) {
let topString: string = this.properties.Top;
if (!topString) {
topString = '(Top property was not defined.)';
}
if (this._topPlaceholder.domElement) {
this._topPlaceholder.domElement.innerHTML = `
<div class="${styles.app}">
<div class="${styles.top}">
<i class="ms-Icon ms-Icon--Info" aria-hidden="true"></i> ${escape(topString)}
</div>
</div>`;
}
}
}
// The extension should not assume that the expected placeholder is available.
if (!this._bottomPlaceholder) {
console.error('The expected placeholder (Bottom) was not found.');
return;
}
if (this.properties) {
let bottomString: string = this.properties.Bottom;
if (!bottomString) {
bottomString = '(Bottom property was not defined.)';
}
if (this._bottomPlaceholder.domElement) {
this._bottomPlaceholder.domElement.innerHTML = `
<div class="${styles.app}">
<div class="${styles.bottom}">
<i class="ms-Icon ms-Icon--Info" aria-hidden="true"></i> ${escape(bottomString)}
</div>
</div>`;
}
}
}
}
2. Go to a modern list in SharePoint Online. This can be a list or a library. To test your extension, append the following query string parameters to the URL:
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":"ClientSideExtension.ApplicationCustomizer","p
Notice that the GUID used in this query parameter has to match the ID attribute of your Application Customizer. This is available in the
HelloWorldApplicationCustomizer.manifest.json file.
You use Header and Footer JSON properties to provide parameters or configurations to the Application Customizer. In this case, you simply output these values. You can also
adjust the behavior based on the properties used in production.
The full URL should look similar to the following:
contoso.sharepoint.com/Lists/Contoso/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"locat
Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages
1. Select Load debug scripts to continue loading scripts from your local host.
You should now see the custom header and footer content in your page.
Next steps
Congratulations, you built your own custom header and footer using the Application Customizer!
To continue building out your extension, see Deploy your extension to SharePoint (Hello World part 3). You will learn how to deploy and preview the Hello World extension in a SharePoint
site collection without using Debug query parameters.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Deploy your extension to SharePoint (Hello World part 3)
4/20/2018 • 5 minutes to read Edit Online
This article describes how to deploy your SharePoint Framework Application Customizer to SharePoint and see it working on modern SharePoint pages.
Be sure you have completed the procedures in the following articles before you begin:
Build your first SharePoint Framework Extension (Hello World part 1)
Use page placeholders from Application Customizer (Hello World part 2)
You can also follow these steps by watching the video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/DzHdVxL A3Pc
cd app-extension
<CustomAction
Title="SPFxApplicationCustomizer"
Location="ClientSideExtension.ApplicationCustomizer"
ClientSideComponentId="46606aa6-5dd8-4792-b017-1555ec0a43a4"
ClientSideComponentProperties="{"Top":"Top area of the page","Bottom":"Bottom area in the page"}">
</CustomAction>
</Elements>
Ensure that definitions are taken into account within the build pipeline
Open package-solution.json from the config folder. The package-solution.json file defines the package metadata as shown in the following code. To ensure that the element.xml file is
taken into account while the solution is being packaged, default scaffolding adds needed configuration to define a feature framework feature definition for the solution package.
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "app-extension-client-side-solution",
"id": "98a9fe4f-175c-48c1-adee-63fb927faa70",
"version": "1.0.0.0",
"features": [
{
"title": "Application Extension - Deployment of custom action.",
"description": "Deploys a custom action with ClientSideComponentId association",
"id": "4678966b-de68-445f-a74e-e553a7b937ab",
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
]
}
}
]
},
"paths": {
"zippedPackage": "solution/app-extension.sppkg"
}
}
Deploy the extension to SharePoint Online and host JavaScript from local host
Now you are ready to deploy the solution to a SharePoint site and have the CustomAction automatically associated on the site level.
1. In the console window, enter the following command to package your client-side solution that contains the extension so that we get the basic structure ready for packaging:
gulp bundle
gulp package-solution
app-extension.sppkg
3. You now need to deploy the package that was generated to the app catalog. To do this, go to your tenant's app catalog and open the Apps for SharePoint library.
4. Upload or drag and drop the app-extension.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint displays a dialog and asks you to trust the client-side
solution.
Note that we did not update the URLs for hosting the solution for this deployment, so the URL is still pointing to https://localhost:4321 .
5. Select the Deploy button.
6. Move back to your console and ensure that the solution is running. If it's not running, execute the following command in the solution folder:
7. Go to the site where you want to test SharePoint asset provisioning. This could be any site collection in the tenant where you deployed this solution package.
8. Select the gear icon on the top navigation bar on the right, and then select Add an app to go to your Apps page.
9. In the Search box, enter app, and then select Enter to filter your apps.
10. Select the app-extension-client-side-solution app to install the solution on the site. When the installation is completed, refresh the page by selecting F5.
When the application has been successfully installed, you can see the header and footer being rendered just like with the debug query parameters.
Next steps
Congratulations, you have deployed an extension to a modern SharePoint page from the app catalog!
You can continue building out your Hello World extension in the next topic, Host extension from Office 365 CDN (Hello World part 4), where you learn how to deploy and load the extension
assets from a CDN instead of from localhost.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Host extension from Office 365 CDN (Hello World part 4)
4/20/2018 • 3 minutes to read Edit Online
This article describes how to deploy your SharePoint Framework Application Customizer to be hosted from an Office 365 CDN and how to deploy that to SharePoint for end users.
Be sure you have completed the procedures in the following articles before you begin:
Build your first SharePoint Framework Extension (Hello World part 1)
Use page placeholders from Application Customizer (Hello World part 2)
Deploy your extension to SharePoint (Hello World part 3)
You can also follow these steps by watching the video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/nh1qFArXG2Y
3. Get the current status of public CDN settings from the tenant level by executing the following commands one-by-one:
Public CDN has now been enabled in the tenant by using the default file type configuration allowed. This means that the following file type extensions are supported: CSS, EOT, GIF,
ICO, JPEG, JPG, JS, MAP, PNG, SVG, TTF, and WOFF.
5. Open up a browser and move to a site collection where you'd like to host your CDN library. This could be any site collection in your tenant. In this tutorial, we create a specific library
to act as your CDN library, but you can also use a specific folder in any existing document library as the CDN endpoint.
6. Create a new document library on your site collection called CDN, and add a folder named helloworld to it.
7. In the PowerShell console, add a new CDN origin. In this case, we are setting the origin as */cdn , which means that any relative folder with the name of cdn acts as a CDN origin.
8. Execute the following command to get the list of CDN origins from your tenant:
Note that your newly added origin is listed as a valid CDN origin. Final configuration of the origin takes approximately 15 minutes, so we can continue creating your test extension,
which is hosted from the origin after deployment is completed.
When the origin is listed without the (configuration pending) text, it is ready to be used in your tenant. This indicates an on-going configuration between SharePoint Online and the
CDN system.
5. Execute the following task to package your solution. This command creates an app-extension.sppkg package in the sharepoint/solution folder, and prepares the assets in the
temp/deploy folder to be deployed to the CDN.
6. Upload or drag-and-drop the newly created client-side solution package to the app catalog in your tenant, and then select the Deploy button.
7. Upload or drag-and-drop the files in the temp/deploy folder to the CDN/helloworld folder created earlier.
8. Install the new version of the solution to your site, and ensure that it's working properly without your locahost hosting the JavaScript file.
Congratulations, you have enabled a public CDN in your Office 365 tenant and taken advantage of it from your solution!
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
See also
Build your first ListView Command Set extension
Build your first Field Customizer extension
Overview of SharePoint Framework Extensions
Build your first Field Customizer extension
7/9/2018 • 11 minutes to read Edit Online
Extensions are client-side components that run inside the context of a SharePoint page. Extensions can be deployed to SharePoint Online, and you can use modern JavaScript tools and
libraries to build them.
You can follow these steps by watching the video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/4wgZy5tm4yo
md field-extension
cd field-extension
yo @microsoft/sharepoint
4. When prompted:
Accept the default value of field-extension as your solution name, and then select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select Field Customizer as the extension type to be created.
5. The next set of prompts ask for specific information about your extension:
Accept the default value of HelloWorld as your extension name, and then select Enter.
Accept the default value of HelloWorld description as your extension description, and select Enter.
Accept the default value of No JavaScript Framework as the framework selection, and select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:
npm shrinkwrap
7. Type the following into the console to start Visual Studio Code.
code .
NOTE
Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your extension.
Note how the default solution structure looks like the solution structure of client-side web parts. This is the basic SharePoint Framework solution structure, with similar configuration
options across all solution types.
8. Open HelloWorldFieldCustomizer.manifest.json in the src\extensions\helloWorld folder.
This file defines your extension type and a unique identifier id for your extension. You need this unique identifier later when debugging and deploying your extension to SharePoint.
The logic for your Field Customizer is contained in the OnInit(), onRenderCell(), and onDisposeCell() methods.
onInit() is where you should perform any setup needed for your extension. This event occurs after this.context and this.properties are assigned, but before the page DOM is ready.
As with web parts, onInit() returns a promise that you can use to perform asynchronous operations; onRenderCell() is not called until your promise has resolved. If you don’t need that,
simply return Promise.resolve<void>(); .
onRenderCell() occurs when each cell is rendered. It provides an event.domElement HTML element where your code can write its content.
onDisposeCell() occurs immediately before the event.cellDiv is deleted. It can be used to free any resources that were allocated during field rendering. For example, if onRenderCell()
mounted a React element, onDisposeCell() must be used to free it; otherwise, a resource leak would occur.
The following are the contents of onRenderCell() and onDisposeCell() in the default solution:
@override
public onRenderCell(event: IFieldCustomizerCellEventParameters): void {
// Use this method to perform your custom cell rendering.
const text: string = `${this.properties.sampleText}: ${event.fieldValue}`;
event.domElement.innerText = text;
event.domElement.classList.add(styles.cell);
}
@override
public onDisposeCell(event: IFieldCustomizerCellEventParameters): void {
// This method should be used to free any resources that were allocated during rendering.
// For example, if your onRenderCell() called ReactDOM.render(), then you should
// call ReactDOM.unmountComponentAtNode() here.
super.onDisposeCell(event);
}
You use the --nobrowser option because you don't need to launch the local Workbench, since you can't debug extensions locally.
When the code compiles without errors, it serves the resulting manifest from https://localhost:4321.
2. To test your extension, go to a site in your SharePoint Online tenant.
3. Move to the Site Contents page.
4. On the toolbar, select New, and then select List.
6. Select the plus sign, and then select Number to create a new Number field for the list.
7. Set the name of the field to Percent, and then select Save.
8. Add a few items with different numbers in the percent field. We'll modify the rendering later in this tutorial, so the different numbers will be presented differently based on your
custom implementation.
Because our Field Customizer is still hosted in localhost and is running, we can use specific debug query parameters to execute the code in the newly created list.
9. Append the following query string parameters to the URL. Notice that you need to update the ID to match your own extension identifier available from the
HelloWorldFieldCustomizer.manifest.json file. For more information, see More details about the URL query parameters.
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&fieldCustomizers={"Percent":{"id":"45a1d299-990d-4917-ba62-7cb67158be16","properties":{"sampleText":"Hello!"}}}
The full URL should look similar to the following, depending on your tenant URL and the location of the newly created list:
contoso.sharepoint.com/Lists/Orders/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&fieldCustomizers={"Percent":{"id":"45a1d299-990d-4917-ba62-7cb67158
Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages
1. Accept the loading of debug manifests by selecting Load debug scripts when prompted.
Notice how the Percent values are now presented with an additional prefix string as Hello!: , which is provided as a property for the Field Customizer.
More details about the URL query parameters
loadSPFX=true ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework is not normally loaded unless at least one extension is
registered. Because no components are registered yet, we must explicitly load the framework.
debugManifestsFile specifies that you want to load SPFx components that are locally served. The loader only looks for components in the app catalog (for your deployed solution) and
the SharePoint manifest server (for the system libraries).
fieldCustomizers indicates which fields in your list should have their rendering controlled by the Field Customizer. The ID parameter specifies the GUID of the extension that should be
used to control the rendering of the field. The properties parameter is an optional text string containing a JSON object that is deserialized into this.properties for your extension.
Key: Use the internal name of the field as the key.
Id: The GUID of the Field Customizer extension associated with this field.
Properties: The property values defined in the extension. In this example, sampleText is a property defined by the extension.
.HelloWorld {
.cell {
display: inline-block;
}
.full {
background-color: #e5e5e5;
width: 100px;
}
}
2. Open the HelloWorldFieldCustomizer.ts file in the src\extensions\helloWorld folder, and update the onRenderCell method as follows.
@override
public onRenderCell(event: IFieldCustomizerCellEventParameters): void {
event.domElement.classList.add(styles.cell);
event.domElement.innerHTML = `
<div class='${styles.HelloWorld}'>
<div class='${styles.full}'>
<div style='width: ${event.fieldValue}px; background:#0094ff; color:#c0c0c0'>
${event.fieldValue}
</div>
</div>
</div>`;
}
3. In your console window, ensure that you do not have any exceptions. If you do not have the solution running in localhost, execute the following command:
4. In your previously created list, use the same query parameter as used previously, with the field being Percent and the ID being updated to your extension identifier available from
the HelloWorldFieldCustomizer.manifest.json file.
5. Accept the loading of debug manifests by selecting Load debug scripts when prompted.
Note how we changed the field rendering style completely. The field value is indicated by using a graphical representation of the value.
<Field ID="{060E50AC-E9C1-3D3C-B1F9-DE0BCAC200F6}"
Name="SPFxPercentage"
DisplayName="Percentage"
Type="Number"
Min="0"
Required="FALSE"
Group="SPFx Columns"
ClientSideComponentId="7e7a4262-d02b-49bf-bfcb-e6ef1716aaef">
</Field>
</Elements>
Ensure that definitions are taken into account within the build pipeline
Open package-solution.json from the config folder. The package-solution.json file defines the package metadata as shown in the following code. To ensure that the element.xml file is
taken into account while the solution is being packaged, default scaffolding added needed configuration to define a feature framework feature definition for the solution package.
{
"solution": {
"name": "field-extension-client-side-solution",
"id": "11cd343e-1ce6-462c-8acb-929804d0c3b2",
"version": "1.0.0.0",
"skipFeatureDeployment": false,
"features": [{
"title": "Field Extension - Deployment of custom field.",
"description": "Deploys a custom field with ClientSideComponentId association",
"id": "123fe847-ced2-3036-b564-8dad5c6c6e83",
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
]
}
}]
},
"paths": {
"zippedPackage": "solution/field-extension.sppkg"
}
}
Deploy the field to SharePoint Online and host JavaScript from local host
Now you are ready to deploy the solution to a SharePoint site and get the field association automatically included in a field.
1. In the console window, enter the following command to package your client-side solution that contains the extension so that we get the basic structure ready for packaging:
gulp bundle
gulp package-solution
field-extension.sppkg
3. You now need to deploy the package that was generated to the app catalog. To do this, go to your tenant's app catalog and open the Apps for SharePoint library.
4. Upload or drag-and-drop the field-extension.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint displays a dialog and asks you to trust the client-side
solution.
Note that we did not update the URLs for hosting the solution for this deployment, so the URL is still pointing to https://localhost:4321 .
5. Select the Deploy button.
6. Go to the site where you want to test SharePoint asset provisioning. This could be any site collection in the tenant where you deployed this solution package.
7. Select the gears icon on the top navigation bar on the right, and then select Add an app to go to your Apps page.
8. In the Search box, enter field, and then select Enter to filter your apps.
9. Select the field-extension-client-side-solution app to install the solution on the site. After the installation is complete, refresh the page by selecting F5.
10. When the solution has been installed, select New from the toolbar on the Site Contents page, and then select List.
15. On your console, ensure that the solution is running. If it's not running, execute the following command in the solution folder:
16. Go to the newly created Invoices list. Add a few items to the list with different values in the Percentage column to determine how the field is rendering without the debug query
parameters.
In this case, we continued to host the JavaScript from the localhost, but you could just as well relocate the assets to any CDN and update the URL to enable the loading of the JavaScript
assets outside of the localhost as well.
The process for publishing your app is identical among the different extension types. You can use the following publishing steps to update the assets to be hosted from a CDN: Host
extension from Office 365 CDN.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
See also
Build your first ListView Command Set extension
Overview of SharePoint Framework Extensions
Build your first ListView Command Set extension
7/9/2018 • 11 minutes to read Edit Online
Extensions are client-side components that run inside the context of a SharePoint page. Extensions can be deployed to SharePoint Online, and you can use modern JavaScript tools and
libraries to build them.
You can follow these steps by watching the video on the SharePoint PnP YouTube Channel:
https://www.youtube-nocookie.com/embed/JBhgdSgWgdM
md command-extension
cd command-extension
yo @microsoft/sharepoint
4. When prompted:
Accept the default value of command-extension as your solution name, and then select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select ListView Command Set as the extension type to be created.
5. The next set of prompts ask for specific information about your extension:
Accept the default value of HelloWorld as your extension name, and then select Enter.
Accept the default value of HelloWorld description as your extension description, and select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:
npm shrinkwrap
7. Next, type the following into the console to start Visual Studio Code.
code .
NOTE
Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your extension.
Note how the default solution structure looks like the solution structure of client-side web parts. This is the basic SharePoint Framework solution structure, with similar configuration
options across all solution types.
Currently, images are not properly referenced unless you are referring to them from absolute locations in a CDN within your manifest. This will be improved in future releases.
The behavior for your custom buttons is contained in the onListViewUpdated() and OnExecute() methods.
The onListViewUpdated() event occurs separately for each command (for example, a menu item) whenever a change happens in the ListView, and the UI needs to be re-rendered. The
event function parameter represents information about the command being rendered. The handler can use this information to customize the title or adjust the visibility, for example, if a
command should only be shown when a certain number of items are selected in the list view. This is the default implementation.
When using the method tryGetCommand , you get a Command object, which is a representation of the command that shows in the UI. You can modify its values, such as title , or visible , to
modify the UI element. SPFx uses this information when re-rendering the commands. These objects keep the state from the last render, so if a command is set to visible = false , it remains
invisible until it is set back to visible = true .
@override
public onListViewUpdated(event: IListViewCommandSetListViewUpdatedParameters): void {
const compareOneCommand: Command = this.tryGetCommand('COMMAND_1');
if (compareOneCommand) {
// This command should be hidden unless exactly one row is selected.
compareOneCommand.visible = event.selectedRows.length === 1;
}
}
The OnExecute() method defines what happens when a command is executed (for example, the menu item is selected). In the default implementation, different messages are shown based
on which button was selected.
@override
public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
switch (event.itemId) {
case 'COMMAND_1':
Dialog.alert(`${this.properties.sampleTextOne}`);
break;
case 'COMMAND_2':
Dialog.alert(`${this.properties.sampleTextTwo}`);
break;
default:
throw new Error('Unknown command');
}
}
You use the --nobrowser option because you don't need to launch the local Workbench, since you can't debug extensions locally.
When the code compiles without errors, it serves the resulting manifest from https://localhost:4321.
2. Go to any SharePoint list in your SharePoint Online site by using the modern experience.
Because our ListView Command Set is hosted from localhost and is running, we can use specific debug query parameters to execute the code in the list view.
3. Append the following query string parameters to the URL. Notice that you need to update the GUID to match the ID of your ListView Command Set Extension available in the
HelloWorldCommandSet.manifest.json file. For more information, see More details about the URL query parameters.
?loadSpfx=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"a8047e2f-30d5-40fc-b880-b2890c7c16d6":{"location":"ClientSideExtension.ListViewCommandSet.CommandBar
The full URL should look similar to the following, depending on your tenant URL and the location of the list.
contoso.sharepoint.com/Lists/Orders/AllItems.aspx?loadSpfx=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"a8047e2f-30d5-40fc-b880-b2890c7c16d6":{"location":"
Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages
1. Accept the loading of debug manifests by selecting Load debug scripts when prompted.
2. Notice the new Command Two button available in the toolbar. Select that button to see the text provided as property for the sampleTextTwo property.
3. The Command One button is not visible based on the code, until one row is selected in the document library. Upload or create a document to the library and confirm that the second
button is visible.
4. Select Command Two to see how the dialog control works, which is used in the default output from the solution scaffolding when the ListView Command Set is selected as the
extension type.
2. In your console window, ensure that you do not have any exceptions. If you do not already have the solution running in localhost, execute the following command:
3. In the list view, use the same query parameters used previously with the ID matching your extension identifier available in the HelloWorldCommandSet.manifest.json file.
4. Accept the loading of debug manifests by selecting Load debug scripts when prompted.
We still have the same buttons in the toolbar, but you'll notice they behave differently if you select them one-by-one. Now we are using the new Dialog API, which can be easily used
with your solutions, even for complex scenarios.
<CustomAction
Title="SPFxListViewCommandSet"
RegistrationId="100"
RegistrationType="List"
Location="ClientSideExtension.ListViewCommandSet.CommandBar"
ClientSideComponentId="5fc73e12-8085-4a4b-8743-f6d02ffe1240"
ClientSideComponentProperties="{"sampleTextOne":"One item is selected in the list.", "sampleTextTwo":"This command is always visible."}">
</CustomAction>
</Elements>
NOTE
While running from localhost the custom action will work on both lists and document libraries, but will not once deployed unless the elements.xml is updated. RegistrationId=100 will only
associate the custom action with lists and NOT document libraries. In order to associate the custom action with document libraries, the RegistrationId must be set to 101. If you would like
the action to work on both lists and document libraries, another CustomAction must be added to the elements.xml file
<CustomAction
Title="SPFxListViewCommandSet"
RegistrationId="100"
RegistrationType="List"
Location="ClientSideExtension.ListViewCommandSet.CommandBar"
ClientSideComponentId="5fc73e12-8085-4a4b-8743-f6d02ffe1240"
ClientSideComponentProperties="{"sampleTextOne":"One item is selected in the list.", "sampleTextTwo":"This command is always visible."}">
</CustomAction>
<CustomAction
Title="SPFxListViewCommandSet"
RegistrationId="101"
RegistrationType="List"
Location="ClientSideExtension.ListViewCommandSet.CommandBar"
ClientSideComponentId="5fc73e12-8085-4a4b-8743-f6d02ffe1240"
ClientSideComponentProperties="{"sampleTextOne":"One item is selected in the list.", "sampleTextTwo":"This command is always visible."}">
</CustomAction>
</Elements>
Possible location values that can be used with a ListView Command Set:
ClientSideExtension.ListViewCommandSet.CommandBar - Toolbar of the list or library
ClientSideExtension.ListViewCommandSet.ContextMenu - Context menu for list or library items
ClientSideExtension.ListViewCommandSet - Register commands to both the toolbar and to the context menu
Ensure that definitions are taken into account within the build pipeline
Open package-solution.json from the config folder. The package-solution.json file defines the package metadata as shown in the following code. To ensure that the element.xml file is
taken into account while the solution is being packaged, default scaffolding added needed configuration to define a feature framework feature definition for the solution package.
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "command-extension-client-side-solution",
"id": "690ae189-a4fc-4b98-8f28-d4ec17448b7a",
"version": "1.0.0.0",
"features": [
{
"title": "Application Extension - Deployment of custom action.",
"description": "Deploys a custom action with ClientSideComponentId association",
"id": "e91d5532-3519-4b50-b55e-b142fc74cd8a",
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
]
}
}
]
},
"paths": {
"zippedPackage": "solution/command-extension.sppkg"
}
}
Deploy the extension to SharePoint Online and host JavaScript from local host
Now you are ready to deploy the solution to a SharePoint site and have the CustomAction automatically associated on the site level.
1. In the console window, enter the following command to package your client-side solution that contains the extension so that we get the basic structure ready for packaging:
gulp bundle
gulp package-solution
command-extension.sppkg
3. Deploy the package that was generated to the app catalog. To do this, go to your tenant's app catalog and open the Apps for SharePoint library.
4. Upload or drag-and-drop the command-extension.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint displays a dialog and asks you to trust the client-side
solution.
Note that we did not update the URLs for hosting the solution for this deployment, so the URL is still pointing to https://localhost:4321 .
5. Select the Deploy button.
6. In your console, ensure that the solution is running. If it's not running, execute the following command in the solution folder:
7. Go to the site where you want to test SharePoint asset provisioning. This could be any site collection in the tenant where you deployed this solution package.
8. Select the gears icon on the top navigation bar on the right, and then select Add an app to go to your Apps page.
9. In the Search box, enter extension, and then select Enter to filter your apps.
10. Select the command-extension-client-side-solution app to install the solution on the site. When the installation is complete, refresh the page by selecting F5.
11. When the application has been successfully installed, select New from the toolbar on the Site Contents page, and then select List.
NOTE
If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
See also
Build your first Field Customizer extension
Overview of SharePoint Framework Extensions
Configure extension icon
3/26/2018 • 2 minutes to read Edit Online
Selecting an icon that illustrates the purpose of your custom command in SharePoint Framework makes it easier for users to find your command among other options visible in the toolbar
or in the context menu. Specifying an icon for a command is optional. If you don't specify an icon, only the command title is displayed in the command bar.
SharePoint Framework supports building the following types of extensions:
Application Customizer
Field Customizer
Command Set
The Command Set is the only type of SharePoint Framework Extension for which you can configure icons.
When deploying Command Sets, you can choose whether their commands should be visible on:
The command bar ( location: ClientSideExtension.ListViewCommandSet.CommandBar )
The context menu ( location: ClientSideExtension.ListViewCommandSet.ContextMenu )
Both ( location: ClientSideExtension.ListViewCommandSet )
Icons defined for the different commands are displayed only for commands displayed in the command bar.
SharePoint Framework offers you two ways to define the icon for your extension:
Use an external icon image
Use a base64-encoded image
{
"$schema": "https://dev.office.com/json-schemas/spfx/command-set-extension-manifest.schema.json",
"id": "6cdfbff6-714f-4c26-a60c-0b18afe60837",
"alias": "WeatherCommandSet",
"componentType": "Extension",
"extensionType": "ListViewCommandSet",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"items": {
"WEATHER": {
"title": { "default": "Weather" },
"iconImageUrl": "https://localhost:4321/temp/sun.png",
"type": "command"
}
}
}
The command icon displayed in the command bar is 16x16 px. If your image is bigger, it is sized proportionally to match these dimensions.
While using custom images gives you flexibility to choose an icon for your command, it requires you to deploy them along with your other extension assets. Additionally, your image might
lose quality when displayed in higher DPI or specific accessibility settings. To avoid quality loss, you can use vector-based SVG images, which are also supported by the SharePoint
Framework.
{
"$schema": "https://dev.office.com/json-schemas/spfx/command-set-extension-manifest.schema.json",
"id": "6cdfbff6-714f-4c26-a60c-0b18afe60837",
"alias": "WeatherCommandSet",
"componentType": "Extension",
"extensionType": "ListViewCommandSet",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"items": {
"WEATHER": {
"title": { "default": "Weather" },
"iconImageUrl": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAAAXNSR0IB2cksfwAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAB/hUlEQVR42u29ebwkWVUn/j03Ip
"type": "command"
}
}
}
Base64 encoding works for both bitmap images, such as PNG, as well as vector SVG images. The big benefit of using base64-encoded images is that you don't need to deploy the web part
icon image separately.
See also
Overview of SharePoint Framework Extensions
Migrating JSLink customizations to SharePoint Framework Field Customizers
3/26/2018 • 10 minutes to read Edit Online
SharePoint Framework is a new model for building SharePoint customizations. If you customized SharePoint fields and list views with JSLink, you might be wondering what the advantages
of migrating them to the new SharePoint Framework are.
First, let's introduce the available options when developing SharePoint Framework Extensions:
Application Customizer. Extend the native "modern" UI of SharePoint Online by adding custom HTML elements and client-side code to pre-defined placeholders of "modern" pages. At
the time of this writing, the available placeholders are the header and the footer of every "modern" page.
Command Set. Add custom ECB menu items or custom buttons to the command bar of a list view for a list or a library. You can associate any JavaScript (TypeScript) action to these
commands.
Field Customizer. Customize the rendering of a field in a list view by using custom HTML elements and client-side code.
Depending on what is the target of your customization, you can leverage any of the above flavors. For example, the Field Customizers are a good replacement for the JSLink customizations
of fields.
Similarities between SharePoint Framework solutions and SharePoint Feature Framework customizations
Nevertheless, both the JSLink customizations and the SharePoint Feature Framework customizations share some similarities.
Provisioning model
Both SharePoint Framework Extensions and user custom actions or the Edit Control Block (ECB) menu item solutions leverage an XML manifest file, which is written with the SharePoint
Feature Framework syntax. Thus, the deployment is based on the same techniques. However, with the new Field Customizers, you can customize the rendering of a field, and not the
rendering of a single view of a list or library. Of course, the custom field can be used in as many lists and libraries as you like.