►
Description
This module will introduce you to extending the SharePoint user interface with SharePoint Framework extensions, including Application Customizers, Field Customizers, and List View Command Sets.
The module is presented by Andrew Connell (Voitanos). Associated training materials are available from GitHub for easy reuse as needed: https://github.com/SharePoint/sp-dev-training-spfx-extensions.
More details on the complete SharePoint Framework training package can be found from http://aka.ms/spfx-training.
You can use these training materials any way you want in new training deliveries or in other presentations. Sharing is caring!
A
What
we're
gonna
cover
in
this
section
are
what
SharePoint
framework
extensions
are
what
the
debugging
and
testing
of
extensions
looks
like
how
we
deploy
them
and
then
we're
gonna.
Look
at
our
first
extension
type
called
an
application
customizer
in
shame
or
SharePoint
framework
extensions
are
going
to
extend
the
SharePoint
user
experience
and
they're
gonna.
A
A
We
also
had
the
ability
to
change
how
fields
will
render
using
jaeik
and
client-side
rendering
that's
now
done
using
field
customizers,
and
then
we
also
had
the
ability
to
do
things
with
buttons
inside
of
menus
context,
menus
for
items
and
toolbars
and
lists
and
libraries,
and
we
call
those
custom
actions
or
command
sets
now
what
our
application
customizers.
These
are
gonna.
Allow
us
to
add
script
to
any
page
and
they're
also
going
to
allow
us
to
have
access
to
the
header
in
the
footer
sections.
A
On
a
page
we
call
these
top
and
bottom
the
field
customizer.
Well,
this
is
the
customizing,
the
rendering
of
a
list
column
in
a
modern
list.
So
you
can
see
here.
The
percent
complete
column
has
got
some
custom,
rendering
that
I've
defined
using
javascript
as
a
custom
field
customizer
and
the
command
set
is
the
other
kind
of
option,
and
this
is
where
we
can
add
a
button
to
our
list
and
library
toolbars
or
to
the
context
menu
of
items
within
a
list.
A
Now
let
me
talk
a
little
bit
about
what
the
project
structure
looks
like
for
a
sharepoint
framework
project.
That's
using
extensions.
We've
seen
this
before
with
webparts
and
it's
basically
the
exact
same
thing:
the
dot
vs
code
file,
our
folder,
that's
created
in
a
project,
is
going
to
contain
vs
code,
specific
files,
things
like
tap
for
running
with
tasks
for
debugging
and
for
doing
different
ups
and
for
configuring
settings.
A
The
config
folder
can
includes
all
of
our
configuration
files
and
that's
gonna
be
useful
for
not
only
bundling,
but
also
for
packaging
up
our
deployment,
sending
it
off
to
a
custom
CDN
if
we
weren't
using
the
office
365
CDN
as
well
as
configuring,
our
start
up
process
when
we
do
development,
the
lib
folder
and
the
dist
folder.
These
are
created
on
the
fly,
as
well
as
the
temp
folder,
when
we
do
builds
and
bundling
of
our
projects.
A
These
are
used
to
we
use
these,
or
these
are
created
to
create
the
temp
files
that
are
created
for
the
different,
build
artifacts
on
their
way
to
being
packaged
and
deployed.
The
node
modules
folder
contains
all
of
our
dependencies
that
our
project
needs.
If
you're
a.net
developer,
you
may
be
familiar
with
the
packages
folder
from
a
nougat
based
project.
A
But
in
the
case
of
an
extension,
it's
also
going
to
contain
the
assets
that
we
need
to
deploy
an
extension
and
we'll
see
that
when
we
get
to
the
deployment
piece
a
little
bit
later
and
then
naturally
the
SRC
folder
or
the
source
folder,
that's
the
main
folder
for
our
project.
It
includes
the
extension,
the
Styles
and
a
test
file
as
well.
Now,
let's
talk
for
a
minute
about
what
the
debugging
and
the
testing
of
extensions
looks
like.
A
Unlike
webparts
extensions
are
going
to
require
a
live,
sharepoint
site
list,
and/or
a
library,
and
we
can
still
build
and
host
the
extensions
projects
locally,
while
we're
testing
and
vote
SharePoint
site.
It's
a
similar
experience
that
we
use
to
hosting
to
using
the
hosted
SharePoint
workbench
for
a
web
part
development,
testing
and
debugging.
Now
one
of
the
nice
things
is
is
that
the
configurations
have
been
added
to
each
project
by
the
SharePoint
framework.
Yeoman
generator.
That's
gonna
help
us
in
simplifying
the
loading
of
these
different
SharePoint
sites,
and
they
really
are
gonna.
A
Do
three
things:
they're
gonna
instruct
the
SharePoint
page
to
load
the
SharePoint
framework,
because
that's
not
necessarily
always
loaded
on
every
page.
It's
only
gonna
be
added
to
pages
that
need
the
SharePoint
framework.
When
there's
a
component
on
the
page,
it's
also
going
to
tell
the
SharePoint
framework
an
additional
location
for
of
a
manifest
file
that
it
should
go
fetch
and
that's
used
to
tell
the
SharePoint
framework
about
our
customization
that
we
create.
A
This
is
gonna
trigger
a
dialog
to
pop
up
for
us
to
make
sure
that
we're
okay
with
loading
unsafe
files,
it's
our
on
say,
file
that
we're
loading,
but
it's
just
a
warning
to
make
sure
that
people
aren't
being
hijacked
or
fooled
into
doing
something
they
shouldn't
be
doing,
and
then
the
third
thing
that
it
does
I
don't
have
it
listed
here.
But
the
third
thing
that
it
will
do
is
it
will
then
tell
the
SharePoint
framework.
A
Now,
when
it
comes
to
deployment
of
an
extension,
the
deployment
is
gonna
be
very
similar
to
webparts,
but
we're
gonna
be
using
the
existing
SharePoint
feature
framework
to
get
these
different
items
provisioned
into
SharePoint
and
under
the
covers
really
webparts
are
doing
the
same
thing,
but
it's
a
little
more
transparent
to
you
when
it
comes
to
webparts,
so
for
an
application,
customizer
and
a
command
set.
We're
using
the
existing
custom
action
feature
framework
element,
type
that
is
going
to
have
some
additional
properties
on
it
to
specify
a
custom
script
component
for
a
field
customizer.
A
The
way
that
this
is
going
to
work
is
you're.
Gonna
have
to
create
a
custom
sight
column
gonna,
do
that
declaratively
using
the
field
schema
from
the
feature
framework
schema
and
in
that
is
when
you
is
also
where
you're
gonna
specify
the
unique
ID
of
the
client-side
component
that
you've
created
so
that
the
SharePoint
knows
what
script
file
it
should
be
loading
to
render
it
out.
A
Some
extensions
that
we
look
at
here
also
support
the
notion
of
a
tenant
wide
deployment,
which
is
another
another
interesting
characteristic
that
we
have
with
the
SharePoint
framework
tenant
wide
deployment
is
going
to
allow
us
to
have
centralized
control,
of
which
extensions
are
available
across
all
site
collections
and
sites
for
your
entire
tenant.
Now
it's
it's
gonna.
A
Allow
us
to
also
enable
or
implement
a
consistent
user
experience
across
all
of
our
sites
and
have
a
consistent,
consistent
deployment
across
all
of
our
sites
and
the
other
nice
thing
about
it
is
that,
with
an
extension,
usually
it
doesn't
it's
not
automatically
added
to
a
site.
You
would
have
to
go,
install
it
on
the
site
when
you
wanted
to
use
it,
but
if
you
use
the
tenant
wide
deployment,
it's
automatic.
This
functionality
is
automatically
going
to
be
enabled
on
all
newly
created
sites.
A
Now
what
this
does
is
that
this
is
gonna
bypass,
the
need
for
installation
of
your
extension
on
each
site
collection,
it's
supported
for
App,
only
application,
customizers
and
ListView
command
sets.
It
doesn't
so
it's
not
supported
for
field
customizers
and
that's
because
that
would
end
up
creating
a
site
column
in
every
single
site
collection
which
may
not
be
what
you're
looking
to
do.
A
Have
the
ability
to
specify
the
public
properties
on
an
extension
across
all
the
sites
and
the
way
that
this
is
this
is
gonna,
be
your
default
experience
for
extensions
B
and
it's
going
to
be
the
default
because
of
the
presence
of
a
new
file
in
the
SharePoint
assets,
folder
called
client-side
instances.
Xml
that's
going
to
be
added
to
your
SharePoint
package.
If
you
don't
want
tenant
wide
deployment
to
be
an
option,
you
delete
this
file
before
deploying
your
project.
Now.
A
One
thing
to
note
about
this
is
that
with
tenant
wide
deployment,
this
is
only
going
to
work.
It's
only
available.
If
you
are
in
SharePoint
Online,
it
does
not
work
in
SharePoint,
Server,
2019
on-premises,
so
going
back
to
the
extensions.
The
way
that
this
works
is
that
there's
a
special
list.
That's
added
to
your
tenant,
scoped,
app
catalog.
A
A
This
is
going
to
allow
you
to
allow
you
to
give
it
a
name
like
saying
this
is
the
contoso
app
insights
when
that
may
not
be
the
actual
name
of
it?
The
location
is
where
this
is
going
to
go,
so
we
have
different
supported
locations
for
application,
customizers
and
ListView
command
sets,
and
the
sequence
is
if
we
have
multiple
extensions
that
we're
deploying
what
is
the
order
that
they
should
be
rendered
or
added
to
the
page,
so
we
can
have
a
little
more
control
over
it.
That
way.
A
A
So
this
these
extension,
this
type
of
an
extension,
is
useful
in
a
couple
different
scenarios,
such
as
adding
script
to
every
page,
adding
a
third-party
library
to
every
page
like
in
the
example
I
gave
a
minute
ago,
as
your
application
insights.
Also,
another
option
is
to
add
a
notice
to
all
pages,
such
as
a
news
or
alert
or
a
privacy
notice.
A
Now
these
placeholders,
where
I
just
mentioned
a
second
ago.
This
is
another
thing
that
if
we
can
take
advantage
of
with
an
application,
customizer
there's
two
well-known
placeholders
that
exist
on
every
page,
the
header
and
the
footer,
the
header
is
gonna,
show
up
pinned
just
below
the
sweet
bar
in
office
365,
while
the
footer
is
gonna,
be
pinned
against
the
bottom
of
the
browser.
Now
keep
in
mind
that
these
are
sticky
that
which
means
they're,
gonna,
they're
gonna
be
persistent
when
you
scroll
the
page
and
they're
always
gonna
be
visible.
A
So
here's
a
code
snippet
of
what
an
application
customizer
looks
like
here
at
the
top
I
have
our
public
properties
that
have
been
defined
on
it,
so
it
just
have
one
called
like
say:
a
prefixed
string
and
then
inside
of
this
placeholder,
it's
extending
the
base,
application,
customizer
class
and
there's
really
only
one
method.
That's
really
interesting
here
and
that's
the
on
an
it
method.
This
is
where
you're
gonna
do
all
of
your
work.
Now.
A
A
In
this
first
demo,
we're
going
to
see
how
we
can
work
with
a
application
customizer
in
a
SharePoint
framework
extension.
So
here
what
I
have
as
a
custom
Iser
that
has
taken
a
hold
of
the
top
placeholder
and
the
bottom
placeholder
and
I've
just
simply
written
out
some
text
to
each
one
of
these
two
different
areas,
really
straightforward
and
really
simple.
A
Now
what
I'd
like
to
do
is:
let's
take
a
look
at
the
code
and
how
we
did
this
so
if
I
come
over
here
to
the
code
and
I,
look
at
the
typescript
file
for
my
extension,
what
I'll
see
here
is
I
have
a
property
of
header
and
footer
that
are
being
defined
here.
But
if
I
scroll
down
a
little
bit
further,
we
will
find
a
section
inside
of
the
application
customizer,
where
I
have
a
reference
to
the
top
and
the
bottom
placeholder.
Now.
A
The
reason
why
I'm
getting
these
references
as
members,
private
members
inside
of
my
web
part
or
inside
of
my
extension,
is
because
you
don't
want
to
have
multiple
handles
to
the
same
placeholder
provider
and
the
reason.
Why
is
that,
if
you
do
that,
you're
gonna
get
an
exception,
so
I'm
keeping
track
of
the
fact
of
which
one
I
have
a
handle
on,
and
in
this
case
here
I've
got
a
reference
to
both
top
and
bottom.
So
what
I
do
is
inside
of
the
on
anit
method.
I'm
gonna
call
a
method
here.
A
A
Now
my
own
dispose
method.
Doesn't
do
anything
it's
right
down
here?
It
just
simply
says
that
it
writes
a
message
out
to
the
console,
but
if
I
had
any
other
handles
on
things
like
timers
or
outstanding
Network
requests
and
stuff,
this
is
that
would
be
a
good
place
where
I
would
clean
those
up
something
into
another
check
to
verify.
Do
you
in
fact
have
a
reference
to
the
top
placeholder
provider?
And
if
you
do,
then
you're
good
shape
continue.
Otherwise
we're
gonna
throw
an
error
because
clearly
something's
wrong.
A
So
now,
I'm
gonna
check
to
see
are
any
properties
defined
and
if
I
did
have
a
property
that
was
defined,
then
our
if
I
do
have
properties
defined.
Then
I
will
come
down
and
grab
the
header
property
for
that.
For
those
properties,
and
in
this
case
here
I'm
checking
to
see
if
I
did
have
a
header
message,
then
I'm
gonna
use
that
otherwise
I'm
gonna
set
it
to
a
default
value
of
the
Hydra
property
was
not
defined
a
little
bit
farther
down
now.
I'm
gonna
go
actually
right
to
that
placeholder.
A
So
I'm
gonna
check
to
see
do
have
a
reference
to
the
div
element
on
the
page,
where
the
top
placeholder
is,
and
that's
indicated,
by
going
to
the
top
placeholders
Dom
element
property
and
if
I
do
that,
I'm
just
gonna
write
out
some
HTML,
so
I'm
right
out
to
the
inner
HTML
property,
a
div
that
contains
a
little
icon
here
and
then,
after
that,
icon
I'm
gonna
write
out
the
header
message.
So
how
is
this
getting
displayed
on
the
page
or
how
am
I
getting
this
is
show
up
on
the
page.
A
You
can
see
here
on
the
page
URL
for
the
other
serve
configuration,
it's
pointing
to
contoso
and
contoso
is
not
a
valid
site,
so
what
I
did
is
I
went
ahead
and
I
used
a
valid
site
that
I
could
use
for
my
testing.
Then
we
can
see
the
additional
information
about.
This
is
a
custom
action.
That's
gonna,
get
added
this
good
right
here
is
the
good
from
the
components
manifest.
A
A
So
you
can
see
one
property
is
the
header
area
of
the
page
and
the
footer
area
of
the
page
and
if
you're
a
call
from
the
demo,
it
had
the
header
area
of
the
page
and
the
footer
area
of
the
page
were
both
displayed
here.
So
that's
all
there
isn't
working
with
a
application.
Placeholder
there
is
another
one
that
I
didn't
show
you
a
bit
farther
down
for
the
bottom
placeholder,
but
the
code,
for
it
is
the
exact
same
as
the
top
placeholder,
and
so
that's
how
we
can
work
with
application.
A
So
a
field
customizer
is
gonna
last
to
customize
the
rendering
of
a
cell
in
a
ListView
display
mode,
it's
similar
to
the
priest,
SharePoint
framework
or
classic
mode
customizations
that
you're
familiar
with
of
client-side,
rendering
and
j/s
link
and
some
really
common
scenarios,
for
it
is
displaying
a
picture
or
an
illustration
in
a
field
instead
of
just
simple
text.
Maybe
you
also
want
to
make
a
field
rendering
a
little
more
interactive,
and
maybe
you
even
want
to
have
every
act
component
be
responsible
for
rendering
out
your
field.
A
So
here's
what
the
class
looks
like
for
this.
What
this
is
is
you're
gonna
have
again
you'll
have
your
properties
at
the
top.
As
you
see
there
and
then
we'll
have
our
field.
Customizer
that
extends
the
base
field
customizer
class.
Now
there
are
a
couple
different
events
here.
You
have
your
own
in
it
just
like
you
had
with
your
application
customizer,
but
the
one
method,
that's
interesting
here.
A
We
all
do
most
of
your
work
is
the
on
render
cell
and
what
this
is
you're
inside
of
this
you'll
be
able
to
say,
event
and
you'll
be
able
to
reference
the
this
Dom
element,
just
like
you
do
with
a
web
part
and
that's
gonna
point
to
the
div,
where
the
cell
is
currently
being
rendered.
So
you
can
then
write
anything
you
want
inside
of
that
div.
Do
you
have
full
control
over
how
all
of
that
stuff
works?
A
Now
when
it
comes
to
the
deployment
of
a
field
customizer
as
a
site
column
or
as
a
deployment
of
field,
customize
you're
gonna
do
that
as
a
site
column,
and
this
is
gonna
look
familiar
to
those
of
you
who
are
used
to
the
feature
framework.
Specifically,
the
field
schema.
The
part
here
that
is
different
for
a
field.
Customizer
are
the
last
two
properties,
the
client-side
component
ID
and
the
client-side
component
properties.
The
component
ID
is
the
gooood
of
the
the
field
customizer
from
his
manifest
file
in
the
project.
A
We'll
see
that
in
the
demo
in
a
minute,
and
then
the
other
part
here
is
of
the
component
properties,
this
is
a
HTML
encoded
string
of
the
JSON
string.
That's
gonna
of
the
object
of
the
public
properties
on
my
item.
So
here
you
can
see.
There
is
a
property
here
called
the
green
men
limit
that
is
set
to
it
looks
like
85%,
and
then
the
yellow
men
limit
is
set
to
70,
and
you
can
see
here
that
I've
had
I
had
to
put
in
these.
These
quotes
that
have
been
escaped.
A
A
Now,
unlike
webparts
extensions,
are
gonna
require
us
to
run
these
in
a
live
SharePoint
list,
and/or
library,
you
can
still
build
and
host
the
extension
project
locally,
just
like
an
app
customizer,
while
you're
testing
it
in
a
remote
SharePoint
site
and
again,
just
like
the
app
customizer
is
very
similar
to
a
web.
Part
Microsoft
has
even
created
some
configurations
for
each
project
that
we'll
see
in
the
demo
in
a
minute
that
we've
done.
It's
done
that
using
the
yeoman
generator.
That's
gonna
simplify
loading
this
on
our
SharePoint
sites.
A
Now,
when
you
want
to
test
how
this
thing
works,
you're
gonna
have
to
specify
the
internal
name
of
the
field
of
an
existing
field
that
you
want
to
associate
the
field
customers
are
with.
So
when
you
deploy
it,
you're
gonna
actually
create
a
site,
column
and
you're.
Gonna
tell
that
site.
Calm
use
this
field
customizer
for
your
rendering,
but
in
development
you
don't
have
to
create
the
site
column
ahead
of
time.
You
can
just
say:
I
want
to
use
an
existing
column
and
I
want
to
test
it.
A
So
this
is
gonna,
let
SharePoint
kind
of
rewire
the
experience
just
while
you're
testing
it
but
again
on
the
deployment
pieces.
I
showed
you
a
minute
ago:
you're
gonna
be
using
the
feature
framework
and
it's
gonna
be
provisioned
as
a
new
site
column
using
the
field
element,
and
then
we've
already
gone
through
these
other
pieces
to
what
the
client-side
component
idea
is.
The
client-side
component
properties
is
and
how
you're
gonna
use
those.
A
A
In
this
second
demo
we're
going
to
look
at
a
field
customizer,
and
in
this
case
you
can
see
one
that
I've
already
created
under
the
%
complete
column.
What
this
is
doing
is
this
is
showing
me
some
information,
but
it's
rendering
out
in
a
custom
way.
So
if
I
actually
come
over
here
to
this
work,
Status
page
and
let's
just
go,
grab
the
link
for
this
page
and
go
to
a
brand
new
browser.
A
You
can
see
here
that
the
value
inside
of
this
list-
they
just
have
numbers
of
95,
80
and
50,
but
when
we
looked
at
it,
we
can
see
here
that
we
actually
have
real
rendering
showing
up
here,
it's
a
little
bit
nicer
to
read,
so
it
shows
a
little
bit
more
of
an
indication
of
of
what's
going
on.
So
how
does
this
work?
A
A
So,
if
I
scroll
down
here
and
we
take
a
look
at
the
on
render
cell
I'm
first
going
to
go,
get
a
reference
or
add
a
CSS
style,
some
styles
to
the
cell,
so
you
see
have
the
Styles
cell
I'm,
adding
in
a
list
of
classes
to
that
cell,
so
I've
gone
ahead
and
if
I
back
up
here,
you
can
see
that
I've
created
a
cell
here
of
an
inline
block
and
then
I've
got
like
a
filled
background
that
I'm
going
to
specify
right
here.
That's
just
all
gray.
A
So
I
come
back
over
here
to
my
code
that
here,
I've
gone
through
and
I've
added.
In
that
background,
for
the
cell
now
I'm
doing
is
I'm
going
to
determine
what
color
and
text
that
I
want
to
use,
and
so
I'm
gonna
do
is
I'm
going
to
take
look
at
the
event
that's
being
passed
in
so
this
on
render
cell
is
gonna
happen.
Every
single
one
of
those
cells
and
the
event
object,
that's
being
passed
in
of
the
event
parameter
is
details
about
the
thing
that
is
the
subject
that
is
triggering
this
event.
A
I'm
gonna
look
at
the
field
value.
So
that's
me
give
me
either
a
95
or
an
80
or
whatever,
and
then
this
check
right
here.
What
this
is
going
to
do
is
this
is
gonna
figure
out
what
what
color
should
be
used
to
display.
So
here,
in
this
case,
I'm
gonna
check
to
see
is
the
number:
is
it
not
a
number
or
is
the
number
equal
to
zero?
And
if
that's
the
case,
then
I'm
just
gonna
write
out,
there's
been
no
progress
and
we
saw
that
in
the
browser
we
can
see.
A
There
was
no
progress
on
this
one,
but
when
there
is
progress,
so
under
the
else
statement,
I'm
going
to
look
at
the
the
value
that's
being
passed
in
and
check
to
see
is
the
number
greater
than
or
equal
to
the
green
limit,
and
if
it
is
we're,
gonna
use
green
as
the
background
color.
Otherwise,
if
it's
yellow
we're
gonna
use,
yellow
as
a
background
color,
and
if
it's
below
that
minimum
limit,
then
it's
not
good.
So
we're
gonna.
A
Consider
that
red
so
I'm
going
to
create
the
red
color
right
here
and
then
every
event
that's
being
passed
in
for
that
cell.
The
reason
the
way
I'm
gonna
deal
with
the
value
coming
from
or
the
the
rendering
that
I
want
to
use
for
that
field
customizer
is
the
Dom
element
is
going
to
point
to
the
div
of
an
item
of
that
column
in
the
list.
A
For
that
specific
list
item
so
I'm
going
to
use
Dom
element
and
then
say
inner
HTML
I'm
going
to
write
out
the
Styles
percent
complete
so
that
style
right
here
is
the
the
percent
complete
and
inside
of
that
I'll
specify
a
fill.
The
background
that
filled
background
that
you
see
here.
That
style
is
given
give
me
a
background
color
for
that
entire
cell.
That's
a
hundred
pixels
wide
equal
to
the
color
of
grey
and
that's
how
I'm
getting
that
little
shaded
gray.
A
If
you
can
see
that
in
your
in
the
video
here,
you
can
see,
I've
got
a
shaded
gray
on
the
background
and
then
I'm
going
to
write
out
the
code
here.
I'm
gonna
write
out.
Another
div
and
the
width
of
that
is
gonna,
be
equal
to
the
percentage,
which
is
just
a
set
of
pixels,
but
I'm
just
gonna
be
using
a
number
from
1
to
100
or
from
zero
to
100,
I,
guess
and
I'll
set
the
background
color
equal
to
this,
and
the
text
color
will
be
black
and
then
I'm.
A
Simply
gonna
write
out
the
value
of
this
text
to
say,
non-breaking
space
followed
by
the
actual
percent
completed
and
that's
how
we
build
a
custom
field,
control
or
cutoff
US
custom
field
customizer.
Now
how
do
we
get
this
to
run
and
see
in
development
mode?
Well,
what
I
have
to
do
is
inside
the
serve
JSON
I
have
to
create
a
configuration,
that'll
load
this
and
get
this
guy
to
work
so,
like
the
other
extensions
I
had
to
change
the
URL
to
be
a
page
that
will
support
these
app
customizers
or
support
these
field.
A
Customizers
and
I
did
that
by
pointing
to
my
work
Status
page
now
it's
a
field
customizer,
and
so
what
I
have
to
do
is
the
value
that
you
see
listed
here
on
number
nine.
This
initially
would
say
the
internal
field
name,
but
I
had
to
change
that
to
be
the
name
of
the
field
where
I
wanted
this
to
show
up
and
I
knew
that
that
was
called
the
percent
complete
with
no
spaces
in
it
all
right,
so
I
said
percent
complete.
A
The
ID
is
the
ID
of
the
component,
which
came
from
his
manifest
and
then
I'm
setting
these
two
properties
that
I
wanted
to
define
when
this
gets
added
to
the
page,
and
so
when
this
runs,
it's
gonna
go
to
this
page
and
it's
gonna
say
replace
the
percent
complete
field
with
this
field
customizer
and
the
field
customizer.
Is
that
ID
with
these
values?
A
If
I
was
going
to
play
this
to
production?
If
I
come
over
here
and
look
at
the
elements
XML,
you
can
see
here
that
I'm
creating
a
new
site
column.
That's
gonna,
be
using
this
component
as
its
rendering
we've
got
our
green
limit.
We've
got
our
yellow
limit
farther
off
the
screen
there,
and
the
name
of
this
field
is
gonna,
be
called
the
SPF
X
percentage.
It
doesn't
matter
that
this
doesn't
match
my
testing
thing,
because
this
or
my
testing
experience
you
saw
a
moment
ago,
because
this
is
what's
gonna
happen
in
production.
A
In
this
last
section,
we're
gonna
look
at
the
third
extension
type,
which
is
a
list
view
command
set,
and
so
we're
gonna
do
the
same
thing
we
did
a
second
ago,
which
is
we're
gonna,
do
an
overview
of
what
these
are
look
at
the
debugging
and
that
in
the
testing
side
of
this
and
then
look
at
what
the
deployment
aspects
are
for
each
one
of
these
things.
As
list
of
you
command
set,
is
gonna.
A
You
can't
see
that
in
the
picture,
but
it's
there
or
you
can
do
both
you're
gonna
also
have
the
ability
to
control
the
visibility
state
of
a
button
based
on
the
state
of
the
current
view,
and
it's
gonna
be
similar
to
the
pre-show
point
framework
classic
mode
customizations
that
you
may
be
familiar
with
of
custom
actions.
Some
example:
scenarios
for
this
you'll
be
able
to
start
an
external
process
or
execute
some
custom
logic
when
these
buttons
are
clicked.
A
A
One
item
selected
and
always
on
take
note
that
you're,
the
IDS
of
your
buttons
should
be
in
all
caps,
should
be
all
alpha,
all
letters,
no
numbers
and
if
you're
gonna,
if
you
need
to
separate
words,
use
the
underscore
you
can
run
into
issues
if
you
deviate
from
that
and
use
lowercase
or
numbers
or
something
other
than
an
underscore.
So
it's
just
letters,
understand,
underscores
and
they
all
must
be.
Uppercase
is
the
general
rule
here
the
icon
image
URL.
That
should
be
a
fully
qualified
URL
to
where
the
image
is
located.
A
If
you
want
to
use
an
image
in
your
button
and
then
you're
gonna
go
work
on
the
code
for
it
now
the
code
for
this,
like
the
other
ones,
we
have
some
public
properties,
we
can
define
an
interface
you
see
at
the
top,
and
then
we
have
a
class.
That's
gonna
extend
the
base
list,
view
command
set
class.
Now
you've
got
three
different
methods
that
you're
gonna
be
interested
in
working
with
here
the
on,
and
it
is
great
for
initialization
stuff.
A
Then
you
have
the
on
list,
view
updated,
and
what
this
is
is.
This
is
gonna,
be
fired
every
single
time
you,
the
the
state
of
your
view
of
the
list
that
you're
currently
on
every
time
the
state
changes
so
like,
for
example,
if
you,
if
you
select
an
item
or
you
unselect
an
item
or
you
filter
or
you
sort
any
time
that
happens,
the
this
is
gonna
get
read.
A
This
is
gonna,
get
called
it's
gonna
lie
to
either
to
do
some
logic,
and
one
of
the
most
common
things
you
would
do
in
here
is
using
the
event
object.
You
would
be
able
to
set
the
the
visibility
property
to
true
or
false,
so
you
can
show
and
hide
the
button
and
that's
where
our
demo
is
gonna.
Do
we're
gonna
show
you
how
to
hide
the
button
based
on
how
many
items
are
selected
and
then,
when
someone
clicks
the
button,
that's
gonna
fire.
A
A
Debugging
and
testing
of
command
sets
is
identical
to
the
other
extensions,
with
the
exception
that
we
have
to
do
this
inside
of
a
live
SharePoint
list
or
library,
I
mean
it's
similar
to
what
a
field
customizer
did
and
the
reason
for
that
is
because
we
have
to
have
a
list
to
be
able
to
test
our
button.
So
it's
gonna,
it's
gonna,
be
added
to
an
existing
list.
The
deployment,
the
way
that
this
is
gonna
work
is
it's
gonna,
be
deployed.
A
The
same
way
that
we
used
to
deploy
custom
actions,
we're
gonna,
use
the
custom
action
element,
but
we're
also
going
to
have
two
additional
properties,
as
you
saw
earlier,
for
the
component
ID
and
the
component
properties.
In
addition,
we
can
also
leverage
tenant
wide
deployment
in
these
as
well.
This
is
gonna
allow
us
to
deploy
this
across,
deploy
our
command
set
across
all
sites
throughout
our
entire
site
collection.
A
If
we
wanted
to-
and
we've
already
gone
through
these
points
as
well,
where
you
have
the
way
that
this
works
is
with
a
custom
list
or
a
special
list
that
lives
in
the
tenant,
scoped
app
catalog
in
your
10
adapt
catalog
and
if
there's
a,
if
there's
an
instance
of
that
list.
Item
in
here,
this
is
where
you'd
be
able
to.
This
is,
what's
gonna,
tell
SharePoint
to
deploy
it
everywhere
across
SharePoint,
so
again,
like
the
other
ones,
the
best
way
to
see
how
this
works
is
with
a
working
demo.
A
So,
let's
switch
over
to
a
demo,
and
let's
see
one
of
these
in
this
last
demo
in
this
module,
I
want
to
show
you
how
we
can
work
with
custom
command.
Sets
which
is
going
to
allow
us
to
have
buttons
on
the
toolbar
or
in
the
context,
menu
of
an
item
that
you
see
down
here
now
up
here.
You
can
see
that
I
have
my
button
up
here
of
always
on
this
is
my
custom
button
and
when
I
click
on
it,
I
can
see
a
little
prefix
of
string.
A
That'll
show
up,
and
then
it's
showing
me
how
many
items
are
selected.
You
also
can
conditionally
show
buttons
and
setting
their
visibility
and
you're
gonna
be
able
to
do
that
by
changed
by
the
counting
the
number
of
items
or
by
some
other
condition.
You
can
set
the
different
conditions
on
what,
when
this
thing
should
or
should
not
show-
and
you
can
do
that,
all
with
your
custom
logic.
A
Now,
in
my
case,
what
I've
done
is
I've
created
it
so
that
the
my
always-on
button
will
always
show
if
I
select
one
item,
I
have
a
one
item
that
will
show
and
if
I
select
two
items,
then
one
item
goes
away
in
two
items
will
show.
So,
let's
see
how
this
works.
One
thing
to
notice,
too,
is
that
you'll
notice
that
let's
grab
item
number
see
if
I
click
this
you
can
see
that
I'm
actually
getting
the
text
for
item
C
showing
up
here
for
his
title.
A
So
let's
see
how
this
works
so
I'm
gonna
come
back
over
here
to
my
code
and
let's
first
inside
of
a
SharePoint
framework
extension
I'm
gonna,
look
at
the
manifest
file.
It's
the
first
thing.
We
should
look
at
because
this
one's
a
little
bit
different
than
other
extensions.
This
one
here
I
have
to
define
the
different
buttons
that
I
want
to
be
able
to
use
in.
My
in
my
component
here
am
I
in
my
custom
command
set.
A
So
here
I've
got
one
called
one
item
selected,
one,
it's
two
item
selected
and
one
is
always
on,
and
they
each
have
titles
in
them.
So
if
I
come
back
over
here
to
the
code,
what
we'll
see
with
this
and
scroll
down,
there's
two
methods
of
interest:
there's
the
on
ListView,
updated
and
there's
the
on
execute.
Now
the
on
ListView
updated
is
going
to
fire
for
every
single
one
of
my
buttons
that
I've
added
to
the
list.
A
Toolbar
or
to
the
the
context
menu
and
when
it
runs
I
can
do
a
check
to
see
which
one
we're
currently
on
and
I
can
check
to
see
and
do
any
other
conditional
stuff
that
I
want
to
do
so.
In
this
case,
one
time
it's
going
to
run
it's
gonna.
This
method
will
always
fire
whenever
there
is
a
view
state
change
to
the
list.
So
it
is
an
item
selected
as
the
sorting
change.
A
This
ID,
then
what
I'm
doing
down
here
is
I'm
checking
to
say
if
one
item
was
selected,
then
set
his
visibility
state
equal
to
this
value,
so
I'm
checking
to
see
how
many
items
are
selected.
If
only
one
item
is
selected,
then
this
should
be
visible,
otherwise
making
it
make
it
hidden
for
the
two
items:
I'm
doing
the
exact
same
things
at
this
time,
I'm
checking
to
see
if
there's
two
items
selected.
So
that's
how
the
one
item
and
two
item
are
both
appearing
and
disappearing
on
the
page.
A
Then
what
happens
when
I
select
one
of
these
things?
Well,
that's
the
on
execute
method.
That's
gonna
fire!
Whenever
the
item
is
clicked-
and
so
you
can
see
here
when
what
am
I
asked
when
item
is
clicked
I'm,
writing
out
a
dialog
message
and
that
dialog
message
is
gonna
write
a
little
prefix
out
with
our
little
sample
string
that
we
had
and
then
I'm
gonna
say
that
one
item
was
selected
and
notice
that
I
can
say,
use
the
event,
that's
passed
in,
say:
dot
selected
rows
get
the
first
item
that
was
selected.
A
He's
gonna
have
one
item
selected
in
this
case
and
I'm
gonna,
say
then
get
the
value
by
the
name
and
show
the
title
field.
So
this
is
going
to
show
me
the
value
of
the
title
field
from
the
selected
rows.
All
right.
It's
pretty
cool!
It's
pretty
easy
actually
to
implement
these
now.
One
thing
to
take
note
of
how
do
I
control,
where
these
are
gonna
show
up.
So
you
can
see
here
in
my
serve
configuration
in
the
location
piece
when
I'm
doing
development.
A
I
can
specify
that
I
want
this
to
be
a
list
view
command
set
in
the
command
bar.
If
I
change
this
from
command
bar
to
command
menu,
it
would
show
up
in
the
context
menu
for
an
item
and
I've
left
it
out
of
both
of
them.
It
would
show
up
everywhere,
in
both
examples,
I'd
show
up
on
the
toolbar
and
it
would
show
up
in
the
in
the
toolbar
and
in
the
context
menu
now
and
as
when
I
go
to
deploy
this
to
production.
A
If
I
look
at
custom
elements
XML,
you
can
see
that
that
is
where
I'm
gonna
specify,
where
I
want
this
button
to
appear
now,
in
this
case,
I
have
three
buttons
in
this
project,
so
that
means
all
of
them
are
gonna,
go
on
the
command
bar.
None
of
them
really
go
in
the
command
menu.
If
I
wanted
to
change
that,
I
had
to
create
different
command
sets,
each
set
would
could
specify
if
it
wanted
to
go
in
the
command
bar
or
if
it
wanted
to
go
into
the
command
set.
A
So
that's
how
I'm
able
to
control
where
these
different
buttons
are
gonna
go,
and
that's
it.
That's
how
that's
how
everything
we
need
to
see
how
to
to
deploy
these
to
a
SharePoint,
to
create
our
own
custom
buttons
in
the
toolbars
and
in
the
ribbons
or
in
the
the
context
menus
for
our
SharePoint
sites.
A
And
so
with
that,
we
looked
at
a
bunch
of
different
things
here
with
extensions,
we
looked
at
what
extensions
were
generally,
how
they
work
and
where
they're
available,
and
then
we
looked
at
each
one
of
the
extensions
in
depth.
We
got
to
see
application
customizers,
we
have
to
see
command
sets
and
field
customizers,
both
the
development,
the
debugging
and
the
deployment
story
for
each
one
of
these
now
I've
added
in
a
bunch
of
references
here
on
where
you
can
learn
more
about
extensions.