WEBVTT

NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com

00:00:01.016 --> 00:00:03.016 align:middle
Let's put Stimulus to the test.

00:00:03.746 --> 00:00:06.596 align:middle
Here's our goal: when we click the play icon,

00:00:06.926 --> 00:00:10.366 align:middle
we're going to make an Ajax
request to our API endpoint...

00:00:10.716 --> 00:00:12.916 align:middle
the one in SongController.

00:00:13.776 --> 00:00:17.396 align:middle
This returns the URL to where
this song can be played.

00:00:18.106 --> 00:00:20.786 align:middle
We'll then use that in JavaScript to...

00:00:20.936 --> 00:00:21.946 align:middle
play the song!

00:00:23.286 --> 00:00:30.686 align:middle
Take hello_controller.js and rename it
to, how about song-controls_controller.js.

00:00:32.286 --> 00:00:37.466 align:middle
Inside, just to see if this is
working, in connect(), log a message.

00:00:38.086 --> 00:00:43.016 align:middle
The connect() method is called whenever Stimulus
sees a new matching element on the page.

00:00:44.136 --> 00:00:48.636 align:middle
Now, over in the template, hello isn't
going to work anymore, so remove that.

00:00:50.106 --> 00:00:54.776 align:middle
What I want to do is surround each
song row with this controller....

00:00:55.086 --> 00:00:57.856 align:middle
so that's this song-list element.

00:00:57.856 --> 00:01:03.936 align:middle
After the class, add {{
stimulus_controller('song-controls') }}.

00:01:03.976 --> 00:01:06.106 align:middle
Let's try that!

00:01:06.486 --> 00:01:10.296 align:middle
Refresh, check the console and...

00:01:10.586 --> 00:01:13.516 align:middle
yes! It hit our code six times!

00:01:14.086 --> 00:01:16.446 align:middle
Once for each of these elements.

00:01:16.966 --> 00:01:21.296 align:middle
And each element gets its own,
separate controller instance.

00:01:22.206 --> 00:01:26.856 align:middle
Okay, next, when we click
play, we want to run some code.

00:01:27.616 --> 00:01:30.696 align:middle
To do that, we can add an action.

00:01:31.676 --> 00:01:36.896 align:middle
It looks like this: on the a tag,
add {{ stimulus_action() }} -

00:01:37.546 --> 00:01:42.866 align:middle
another shortcut function - and pass this the
controller name that you're attaching the action

00:01:42.866 --> 00:01:48.876 align:middle
to - song-controls - and then a method inside
of that controller that should be called

00:01:48.876 --> 00:01:50.486 align:middle
when someone clicks this element.

00:01:50.916 --> 00:01:52.376 align:middle
How about play.

00:01:53.406 --> 00:01:59.576 align:middle
Cool huh? Back in song controller, we
don't need the connect() method anymore:

00:02:00.076 --> 00:02:05.006 align:middle
we don't need to do anything each
time we notice another song-list row.

00:02:05.526 --> 00:02:08.366 align:middle
But we do need a play() method.

00:02:08.366 --> 00:02:12.976 align:middle
And like with normal event listeners,
this will receive an event object...

00:02:13.416 --> 00:02:16.526 align:middle
and then we can say event.preventDefault()

00:02:16.836 --> 00:02:20.286 align:middle
so that our browser doesn't
try to follow the link click.

00:02:21.446 --> 00:02:24.206 align:middle
To test, console.log('Playing!').

00:02:26.576 --> 00:02:27.716 align:middle
Let's go see what happens!

00:02:28.196 --> 00:02:29.476 align:middle
Refresh and...

00:02:29.786 --> 00:02:32.726 align:middle
click. It's working.

00:02:33.126 --> 00:02:37.256 align:middle
It's that easy to hook up an
event listener in Stimulus.

00:02:37.736 --> 00:02:39.746 align:middle
Oh, and if you inspect this element...

00:02:40.236 --> 00:02:44.296 align:middle
that stimulus_action() function
is just a shortcut

00:02:44.296 --> 00:02:48.776 align:middle
to add a special data-action
attribute that Stimulus understands.

00:02:50.316 --> 00:02:54.396 align:middle
Ok, how can we make an Ajax call
from inside of the play() method?

00:02:55.086 --> 00:02:58.826 align:middle
Well, we could use the built-in
fetch() function from JavaScript.

00:02:59.196 --> 00:03:03.836 align:middle
But instead, I'm going to install
a third-party library called Axios.

00:03:04.796 --> 00:03:12.436 align:middle
At your terminal, install it by saying: yarn
add axios -- dev We now know what this does:

00:03:13.156 --> 00:03:16.756 align:middle
it downloads this package into
our node_modules directory,

00:03:17.376 --> 00:03:20.876 align:middle
and adds this line to our package.json file.

00:03:21.726 --> 00:03:27.666 align:middle
Oh, and side note: you absolutely
can use jQuery inside of Stimulus.

00:03:28.166 --> 00:03:31.826 align:middle
I won't do it, but it works
great - and you can install -

00:03:32.036 --> 00:03:35.246 align:middle
and import - jQuery like any other package.

00:03:35.996 --> 00:03:38.036 align:middle
We talk about that in our Stimulus tutorial.

00:03:38.906 --> 00:03:42.126 align:middle
Ok, so how do we use the axios library?

00:03:42.576 --> 00:03:45.076 align:middle
By importing it!

00:03:45.076 --> 00:03:50.746 align:middle
At the top of this file, we're already importing
the Controller base class from stimulus.

00:03:51.656 --> 00:03:55.176 align:middle
Now import axios from 'axios'.

00:03:56.456 --> 00:04:01.506 align:middle
As soon as we do that, Webpack Encore
will grab the axios source code

00:04:01.856 --> 00:04:05.236 align:middle
and include it in our built JavaScript files.

00:04:05.966 --> 00:04:11.086 align:middle
Now, down here, we can say
axios.get() to make a GET request.

00:04:11.826 --> 00:04:14.656 align:middle
But... what should we pass for the URL?

00:04:15.446 --> 00:04:19.906 align:middle
It needs to be something like /api/songs/5...

00:04:20.526 --> 00:04:24.906 align:middle
but how do we know what the
"id" is for this row?

00:04:26.036 --> 00:04:30.706 align:middle
One of the coolest things about Stimulus
is that it allows you to pass values

00:04:30.706 --> 00:04:33.816 align:middle
from Twig into your Stimulus controller.

00:04:34.896 --> 00:04:39.776 align:middle
To do that, declare which values
you want to allow to passed

00:04:39.776 --> 00:04:46.336 align:middle
in via a special static property:
static values = {}.

00:04:46.336 --> 00:04:52.746 align:middle
Inside, let's allow an infoUrl
value to be passed.

00:04:53.616 --> 00:05:00.156 align:middle
I totally just made up that name: I'm thinking
we'll pass in the full URL to the API endpoint.

00:05:01.026 --> 00:05:03.706 align:middle
Set this to the type that this will be.

00:05:04.006 --> 00:05:05.096 align:middle
So, a String.

00:05:07.026 --> 00:05:11.676 align:middle
We'll learn how we pass this value from
Twig into our controller in a minute.

00:05:12.196 --> 00:05:19.816 align:middle
But because we have this, below, we can
reference the value by saying this.infoUrlValue.

00:05:21.386 --> 00:05:23.426 align:middle
So how do we pass that in?

00:05:24.186 --> 00:05:29.636 align:middle
Back in homepage.html.twig, add a second
argument to stimulus_controller().

00:05:30.456 --> 00:05:34.796 align:middle
This is an array of the values you
want to pass into the controller.

00:05:35.296 --> 00:05:38.176 align:middle
Pass infoUrl set to the URL.

00:05:39.176 --> 00:05:41.796 align:middle
Hmm, but we need to generate that URL.

00:05:42.376 --> 00:05:44.186 align:middle
Does that route have a name yet?

00:05:44.766 --> 00:05:49.716 align:middle
Nope! Add name: 'api_songs_get_one'.

00:05:50.236 --> 00:05:52.866 align:middle
Perfect. Copy that...

00:05:53.196 --> 00:05:59.356 align:middle
and back in the template, set infoURl
to path(), the name of the route...

00:05:59.826 --> 00:06:02.536 align:middle
and then an array with any wildcards.

00:06:03.986 --> 00:06:06.496 align:middle
Our route has an id wildcard.

00:06:07.526 --> 00:06:13.276 align:middle
In a real app, these tracks would probably
each have a database id that we could pass.

00:06:13.926 --> 00:06:15.496 align:middle
We don't have that yet...

00:06:15.496 --> 00:06:20.166 align:middle
so to, kind of, fake this,
I'm going to use loop.index.

00:06:20.316 --> 00:06:30.716 align:middle
This is a magic Twig variable: if you're inside
of a Twig for loop, you can access the index -

00:06:30.846 --> 00:06:34.836 align:middle
like 1, 2, 3, 4 - by using loop.index.

00:06:35.336 --> 00:06:37.766 align:middle
So we're going to use this as a fake ID.

00:06:38.236 --> 00:06:43.536 align:middle
Oh, and don't forget to say id: then loop.index.

00:06:43.646 --> 00:06:44.526 align:middle
Testing time!

00:06:45.186 --> 00:06:52.566 align:middle
Refresh. The first thing I want you
to see is that, when we pass infoUrl

00:06:52.566 --> 00:06:54.856 align:middle
as the second argument to stimulus_controller,

00:06:55.266 --> 00:07:01.766 align:middle
all that really does is output a very special
data attribute that Stimulus knows how to read.

00:07:02.276 --> 00:07:04.996 align:middle
That's how you pass a value into a controller.

00:07:05.736 --> 00:07:07.686 align:middle
Click one of the play links and...

00:07:08.436 --> 00:07:13.876 align:middle
got it. Every controller object
is passed its correct URL!

00:07:15.216 --> 00:07:17.826 align:middle
Let's celebrate by making the Ajax call!

00:07:18.126 --> 00:07:25.976 align:middle
Do it with axios.get(this.infoUrlValue)
- yes, I just typo'ed that,

00:07:26.216 --> 00:07:32.556 align:middle
.then() and a callback using an arrow function
that will receive a response argument.

00:07:33.386 --> 00:07:36.256 align:middle
This will be called when the Ajax call finishes.

00:07:36.926 --> 00:07:38.666 align:middle
Log the response to start.

00:07:40.066 --> 00:07:43.666 align:middle
Oh, and fix to use this.infoUrlValue.

00:07:46.106 --> 00:07:47.636 align:middle
Alrighty, refresh...

00:07:47.786 --> 00:07:49.456 align:middle
then click a play link!

00:07:50.196 --> 00:07:52.596 align:middle
Yes! It dumped the response...

00:07:53.156 --> 00:07:55.076 align:middle
and one of its keys is data...

00:07:55.336 --> 00:07:57.756 align:middle
which contains the url!

00:07:58.346 --> 00:08:00.226 align:middle
Time for our victory lap!

00:08:01.366 --> 00:08:06.696 align:middle
Back in the function, we can play that
audio by creating a new Audio object -

00:08:07.146 --> 00:08:12.286 align:middle
this is just a normal JavaScript object
- passing it response.data.url...

00:08:13.656 --> 00:08:16.106 align:middle
and then calling play() on this.

00:08:17.946 --> 00:08:18.796 align:middle
And now...

00:08:19.346 --> 00:08:20.786 align:middle
when we hit play...

00:08:22.936 --> 00:08:26.426 align:middle
finally! Music to my ears.

00:08:27.656 --> 00:08:31.266 align:middle
If you want to learn more about
Stimulus - this was a bit fast -

00:08:31.496 --> 00:08:34.026 align:middle
we have an entire tutorial about it...

00:08:34.026 --> 00:08:35.346 align:middle
and it's great.

00:08:36.226 --> 00:08:41.456 align:middle
To finish off this tutorial, let's
install one more JavaScript library.

00:08:42.166 --> 00:08:47.326 align:middle
This one will instantly make our
app feel like a single page app.

00:08:47.716 --> 00:08:48.676 align:middle
That's next.

