AngularJS - Custom Components - Part 2

Uploaded by johnlindquist on 15.05.2012


Let's take the Markdown component we started in the
previous video tutorial, and add an Edit Mode
and a Preview Mode.
So the first thing we're going to need is a template with a
text area in it.
We need somewhere to actually edit the markdown.
So if I drop in this template and hit refresh, you'll see
nothing is showing up, and that's because if we look at
it, you'll see that we have our Markdown Element with
nothing inside of it.
That means that in this Linking Function, at this
point this element has already been
rendered from this template.
So it hits this point, and we already have the text area.
And when we try and get the content from it, the text from
it, it's already empty, because there's nothing inside
of it, and we're basically replacing it with nothing.
So while the Linking Function is great for things like
adding watchers to the scope, or adding properties to the
scope to expose them to the HTML, or manipulating the
actual DOM element, accessing the attributes.
It's really not the place where you can do any sort of
template manipulation.
So, I'm just going to delete the linking function for now,
hit refresh, and you'll see that we now have a text area.
So, this is great so far.
But what we need is this Markdown content so that we
can edit it.
Now, how we're going to get this is using a process called
Transclusion, which is pretty simple, even though it's a
long word that may not make sense.
So we'll use the word Transclude.
Just set it to true.
And then grab the content using this attribute.
And all this is really doing is kind of yanking this
content out of this Markdown Element, storing it for later
when you need it in a template, and then it's going
to drop it in wherever you use this attribute.
So if I refresh, you'll see it didn't quite work, but it
actually kind of did.
Because if you look in this text area, you'll see we have
a span that's wrapped our content.
And while this is useful for probably 99% of the scenarios
you'd use Transclusion for, for a text area it's not
exactly what we need.
So we're going to have to do a bit of custom template
manipulation, rather than using this
template helper property.
And the place that we do that is in a Compile Function.
So I'm going to delete the template, delete the
Transclusion process, and just set up our Compile function.
Now you'll see that the parameters here are a
tElement, tAttributes, and the Transclusion function.
We're really going to just worry about this tElement,
which is the Template element, or tAttributes is template
So it's the template before it's actually kind of rendered
out and prepared for the Linking Function.
So from our Template Element, we can grab the
content from it.
And this is going to be the Markdown.
So the content at that point is going to be the markdown.
And then we can do a custom template manipulation.
And so we'll set up our template here.
We'll just say that this is a text area, just like before.
And then we'll just name this Edit Template.
And then in RT Element, we can replace the HTML
with our Edit Template.
So if we refresh now, you can see we're
back where we started.
We still have nothing in it because we haven't put the
Markdown content in there.
And the way that we can do that is by simply using the NG
model, bind that to the Markdown, and then exposing
the Markdown on the scope.
So to do anything on the scope, you'll see that we
can't do that in our Compile Function, because the scope
isn't ready yet.
So we need to do that in our Linking Function.
The way to access the Linking Function at this point is by
returning it from the Compile Function.
If you try and do it the other way where you would say
something like link function, that's not going to work at
all because it's a function now that's returned from our
Compile Function.
It wouldn't be called any other way right now.
So, we'll return it, and we'll just assign a property of
scope Markdown is equal to the Markdown that we yanked out
And so we're kind of doing Transclusion
by hand right now.
So if I refresh now, you'll see we have our content.

So, so far so good.
The next step is to hide this, hide the Edit mode, when I
double click on it.
So we'll set up a way of hiding and showing it.
We'll just say, only show this when Is Edit Mode is true.
If I refresh, Is Edit Mode defaults to false.
So let's default it to true instead.
So Is Edit Mode is true.
Refresh and it shows up.
And then we'll set up another.
We'll set up our click handler here and
say, switch to Preview.
So whenever I switch the Preview Mode, I'll say scope ,
switch to Preview, to Function, and we'll say scope
Is Edit Mode equals false.
And this should make it hide.
So doubleclick, and that goes away.
That's because, NG Show, when this is true, it'll show, when
it's false, it'll hide.
So, now that we have it hiding, we need to set up the
other half of our template, which is the Preview Mode.
So we'll just set up a div here.
And we'll put this [? something ?]
called Preview in it.
And we'll say, NG Show, actually NG
Hide, Is Edit Mode.
And this is just the inverse of what we
have in our Edit Template.
Because this is basically going to say when Is Edit Mode
is true, then hide it.
When Is Edit Mode is false, then show it.
So it's just kind of switching back and forth.
So if we refresh again, doubleclick, you'll see
nothing has happened.
And that's because we haven't added our Preview Template to
our element.
So we'll just go ahead and append this, and that'll be
our Preview Template.
Hit refresh, doubleclick, and you'll see our Preview
Template shows up.
And if we doubleclick on this, we won't have
to switch back over.
So let's say NG doubleclick, switch to Edit, and then we
can set up an Edit Function.

Just duplicate this.
And we'll call this Switch to Edit.
Switch to Edit.
And then instead of false, this can be true.
So if I refresh, and I doubleclick, and doubleclick,
then doubleclick, you see we're toggling back and forth
between our Edit Mode and Preview Mode.
Edit Mode and Preview Mode.
So, really the last thing to do here is, that when we
switch to the Preview Mode, we'll want to render out this
content using that Show Down Converter.
So we'll say, make HTML scope Markdown.

And that'll be our rendered HTML from the Markdown.
And then what we need to do is replace the Preview Template
element with our make HTML.
Now, the way I prefer to do this, you
can do it a few ways.
But what I'm going to do is, I'm going to
take the Preview Template.
I'm going to render it out as an element first using this
Angular Element Method.
So I'll pass on the Preview Template, and from here I can
get a reference to our Preview Element.
And then instead of appending the template, I can append the
element so that anywhere else in here, I have a reference to
the Preview Element.
I can say Preview Element, replace with make HTML.
So if I refresh now, when I doubleclick, you'll see that
now it renders out the Markdown as proper HTML.
And I can edit this to say whatever.
Then doubleclick.
And you can see it's updating, just as we want.
Now you may think that this is great and we're done, but
there's actually a couple more things to point out just as
general tips.
The first thing is, if you duplicate this, and then I
refresh, you'll see, oh look it's awesome.
We have two components running at the same time.
But what happens if I start typing in one of them?
It starts editing it in the other one.
And if I doubleclick, everything starts breaking.
This is because we're not isolating the scope to just
this component.
The scope is being shared across the parent scope.
So anything I change in here is going to go into the parent
scope of both of these components and be edited or
updated across the components.
So we need to do is create something called an Isolate
scope here.
Typically, you could add properties to that whatnot.
But for this scenario, we don't even need
properties on it.
We just need an Isolate scope.
And then we can run these
individually without impacting.
I doubleclick this one, and say, the other.
And doubleclick.
You can see I can switch each of these components
individually and they can behave isolated from the other
ones, using the Isolate scope.
Now, the last thing to point out is, if someone else
creates a component called Markdown, and you have your
component called Markdown they may start
overriding each other.
So it's usually a best practice to just add your own
namespace here.
So I'm going to put JL Markdown, and just rename this
top Markdown to JL Markdown.
And what that means is if someone else hands me a
component called Markdown, I could just have my JL Markdown
component work without having to worry about interfering
with this one.
So you can see that this is working fine, and I can
doubleclick and switch between the two modes.
And it's not worrying about this other Markdown component
that someone else may have given me.
So it's always a good practice to use a name space whenever
you create your own components.
So as a quick review, we did quite a bit in this tutorial.
We switched over from using a Linking Function, to using a
Compile Function.
The reason being, we needed to custom edit our templates.
We did Transclusion, and then we kind of did Transclusion by
hand, by grabbing out the content of the original
template element.
We set up a way to switch between our two modes: Preview
Mode, and Edit Mode.
And then we also found out how to grab an element from our
rendered component, so that we can update a specific element
inside of our component later on.
Hopefully this has helped you understand components a bit
better, and thanks for watching.