NgTemplateOutlet in Angular - Everything You Have to Know (2022)
Aug 15, 2023
NgTemplateOutlet in Angular - Everything You Have to Know (2022)
This video will teach you how to utilize an Angular ngTemplateOutlet directive to create reusable components with customizable and extensible views. You will learn everything you have to know about this directive. We will cover all available features like creating views from templates, providing template context data, and controlling the proper Angular Dependency Injection flow. So if you watch the video until the end, you can be sure that you will be able to handle 80% of all possible use cases related to component view customization. 💥 Become a PRO with my in-depth Angular Forms Course💥 🔗 10% discount for the first 10 students - https://bit.ly/advanced-ng-forms-disc … 🕒 Time Codes: 00:00:00 - Intro; 00:00:58 - Project Overview; 00:03:17 - Describing the Problem; 00:04:49 - How to create Embedded Views in Angular; 00:10:54 - Let’s meet [ngTemplateOutlet] directive; 00:12:43 - Conditionally Rendering ng-templates; 00:16:38 - Introducing Template Context; 00:24:01 - Controlling Parent Injector for components in NgTemplates; 00:30:09 - Recap things we learned; 00:32:14 - Disadvantages of [ngTemplateOutlet] directive; 00:34:00 - Outro; 🔗 Project Code on GitHub:https://github.com/DMezhenskyi/angula … (initial state in main branch) 🙌 Support Dmytro https://bit.ly/donate-to-decoded-fron … 💡 Short Frontend Snacks (Tips) every week here: Twitter - https://twitter.com/DecodedFrontend Instagram - https://www.instagram.com/decodedfron … LinkedIn - https://www.linkedin.com/in/dmezhenskyi #ng #angular #angular15
Content
0 -> this video will teach you how to utilize an
angular ngTemplateOutlet directive to
5.64 -> create reusable components with customizable
and extensible Views you will learn everything
11.22 -> you have to know about this directive because
I'm going to cover all its available features
16.38 -> like creating views from angular templates how to
provide template context data and how to control
23.76 -> the proper angular dependence injection flow in
the embedded views so if you watch this video
30.06 -> Until the End, you can be sure that you will be
able to solve 80% of use cases where you
37.38 -> need to implement customizable view for your
angular components if you have first time on
42.78 -> my channel my name is Dmytro Mezhenskyi and here
you can find a lot of advanced angular tutorials
48.18 -> and courses you can check them out later but
now let's get started and enjoy this video
58.56 -> all right let's get started and let me very
quickly onboard you and demonstrate the current
65.16 -> application what kind of problems this application
has and how we are going to fix those problems
73.26 -> uh so as you can see I've got some angular
component that renders the weather forecast and
81.24 -> it also has couple of buttons that perform some
action so we can refresh data of this widget and
88.8 -> we can copy information to our clipboard in order
to you know paste it somewhere of course all this
96.54 -> data and actions those are mocked data I didn't
want to bring the real implementation because I
103.86 -> wanted to keep stuff simple um so yeah this is
how it looks like and there is our component
111.72 -> rendered right here and here you can see the
implementation of this component as you can see
117.9 -> pretty straightforward we have just some template
that renders some data this data comes from some
126.12 -> certain State this state is represented as a separate service that is provided on the
134.16 -> for the injector of the wizard
weather widget which means that
140.46 -> uh those Services they will be single tones in
scope of this component and all its children right
150.42 -> the same for widget actions uh widget actions
those are set of uh just mocked services that
159 -> supposed to perform some useful actions and uh
yeah this is how it looks like you can see pretty
166.32 -> straightforward widget state is also very very
simple and what is what else I am this inject
175.56 -> function for those who just started with angular
this is same as an injection via Constructor so
183.3 -> you could see probably the construction like
this one right and this is pretty much the
190.38 -> same as this notation right this is just a new
way to do that all right and now let's quickly
198.24 -> talk about problems and limitations the problem
has and actually the biggest problem here is the
205.14 -> component template because if you have a look
at it you can easily notice that that template
211.86 -> is completely hard coded and you cannot change
it you cannot customize it and it might be a big
219.06 -> problem if you decide to distribute this component
as a part of some component library or if you need
226.2 -> to reuse this component in in other part of your
application but you have to change somehow look
232.2 -> and feel of this component it is not possible
and it is a problem and I'm going to tell you in
238.44 -> advance that there are a couple of ways of how to
customize the view of angular components the first
244.74 -> way is to use NG template oh sorry NG content
directive it is also known as a Content projection
251.64 -> and another approach is to create embedded view
from angular templates and this is exactly the
258.3 -> approach I'm going to use in this video because
I find it a bit more flexible compared to content
265.92 -> projection but if you'd like to learn more about
content projection as well uh please let me know
272.1 -> about that in the comments under this video and
hit thumbs up if I uh get enough let's say 1
279.6 -> 000 likes under this video I will recognize that
this topic might be interesting for you and I will
285.18 -> create a dedicated uh video about that but now
let's move forward let's move forward and let's
291.12 -> quickly talk about how do we create uh embedded
views in angular so in order to create embedded
298.8 -> view in angular we need to have basically
two things we have to have some container
305.1 -> it's kind of Encore where exactly in the view
needs to be rendered there embedded View and
313.98 -> then we have to have the template that needs to
be instantiated and eventually rendered right
320.58 -> right so the container can be actually any HTML
note yeah we could create some another div and
330.42 -> Market as a container using the template variable
yeah and if we want to create angular template
338.34 -> from some piece of HTML code then we have to use
the NG template and place the HTML that is going
347.46 -> to be the angular template right between those
two tags and what is interesting about NG template
354.36 -> is that it is lazy so if I save it right now you
can see that everything disappeared it is because
362.88 -> we have to explicitly create the view from this
template and only then it will be visible so how
371.52 -> we usually create the embedded view in order to do
that we have to get reference to those two things
378.6 -> to the container and to the NG template so let
maybe name it as a as a default widget header and
386.7 -> then we can easily get reference to them by using
the huge child decorator so I get reference first
394.62 -> to the container and here is very important thing
if I leave it as it is then I will get reference
403.32 -> to the native div element and this is not what I'm
going to achieve I want to read from here the view
411.3 -> container ref right and if I want to get reference
to it I have to specify the config object for the
418.74 -> view child and provide here the read property and
say what exactly I want to read from this node and
425.76 -> from here I'm going to read The View container ref
like that so here I have to create a property here
433.74 -> we go and it's going to be the instance of view
container ref obviously right and then I have to
440.1 -> do the similar thing for the default widget header
so let's create another view child get a reference
448.8 -> to the default widget header template here I
don't need to specify anything because I need
454.2 -> to gather a direct reference to the NG template
right so let's name it header template and it's
461.64 -> going to be the template reference reference to
the template right and let it be any for now we
470.22 -> will talk about this type later in this video but
it is not enough those two just references right
478.26 -> and because we get references using view child it
means that those guys they will be available only
485.76 -> when the component view is instantiated and we
have a dedicated lifecycle hook for that called
492.42 -> and G after view in it right and inside this
lifecycle hook uh those guys as I said will be
500.28 -> available so I can use my container right and call
the method create embedded View and this method
509.34 -> expects that template that needs to be rendered
and I already have such a reference and it is
516 -> a header template property so like that and if I
save it right now you can see that the header view
524.52 -> is back and let's have a look how it looks in the
HTML so here is the our widget header and this is
533.88 -> the container right this is exactly this div and
next to the container there were they were Android
541.2 -> widget title and widget subtitle and those guys
they are coming from the angular template that
547.44 -> we created before I know you might be slightly
confused because you probably expected that the
554.04 -> template will be rendered inside the container
right but no it will be rendered next to them
561.06 -> container node and if you want to get read from
this HTML tag you can always use such a thing
570.66 -> called NG container and in this case you can see
that that empty div has disappeared because any
579.18 -> container it is being rendered eventually into
nothing yeah it works just like a placeholder
586.14 -> for some HTML notes but let's quickly get back
to our current implementation and the way we
593.58 -> implemented this feature right now it is so
called declarative Paradigm in programming
600.24 -> because we explicitly specify steps that needs to
be performed in order to get some desired result
608.28 -> yeah so we say that okay get a reference to The
Container get the reference to the header template
614.88 -> then inside NG after view you need lifecycle hook
create the embedded view blah blah blah blah blah
621.24 -> so we describe how things needs to be done from
Another Side there exists declarative parting
629.64 -> that describes what needs to be done for instance
I need to have embed that you created so here is
637.08 -> the template please create it I don't care how it
will be done I just need the final result so this
643.98 -> is the declarity of uh Paradigm in programming and
usually declarative programming is more readable
652.32 -> and easier to understand and in order to implement
this current feature we have right now but using
660.9 -> a declarative way we have to use NG template
Outlet directive that allows us to do that so
669.96 -> finally we started to talk about this directive
because I don't want just to show the feature I
676.38 -> want to teach you why this feature exists and
which problems does it solve so how it would
683.64 -> look like when we apply the NG template Outlet
directly so I can completely remove this stuff
689.64 -> then we obviously have to import this directive
yes so let's do that so I type NG template Outlet
697.08 -> or you could inject also a common model it is part
of the common model but yeah as you want and once
703.8 -> we have this directive imported we can apply
it to our NG container just like that and as a
710.7 -> value for it we have to provide a reference to the
template that needs to be eventually rendered so
717.3 -> like that and as you can see it works the same
way but it is more readable and less code needed
726.3 -> in order to achieve the same goal and I can also
remove all those stuff as well nice and there is
733.44 -> no any magic here actually under the hood if we
have a look at the source code of this directive
739.26 -> you can see that it does pretty much the same
yeah it has more like conditions whatever but
745.26 -> eventually it has also view container ref
and it creates embedded View and provides
750.9 -> the template that needs to be rendered and then
context injector like those stuff we will cover
757.74 -> late in this video but in a nutshell it is pretty
much the same what we have implemented just couple
763.38 -> of minutes ago all right now what benefits we can
get from refactoring our code to using a template
772.38 -> Outlet Plus uh angular template it means that here
we can dynamically provide any template we want we
784.32 -> can allow user to provide alternative templates we
can do it by using just regular inputs so I create
792 -> some separate input I name it like header template
I say that it needs to be the template ref again
799.98 -> so far it is any type and having that I can just
do something like that I can say that okay render
808.92 -> the template that user provided via component
input or if it's not provided then use default
817.02 -> widget header as a fallback and that's it so I
can save it you can see that nothing has changed
823.92 -> but now I can go to app component and create some
new NG template and I can say here that this is
833.28 -> some alternative widget header and there inside I
can play some alternative template right so I can
841.14 -> create something like that and here play something
like today's weather yeah and then the reference
847.68 -> to this template I can easily provide via this new
header template input just like that and if I save
856.08 -> it right now you can see that the header got the
new template that was provided from outside so
864.06 -> we replaced the default header with the new one
and if I remove this input from here it will fall
872.46 -> back to the default one right so this is the first
cool thing that you can Implement using ng10 blade
880.02 -> Outlet directive and yeah another thing I forgot
to say about the style so most probably you want
886.08 -> to apply some styles for this new alternative
template you can Define Styles in the component
892.44 -> where this template is declared so I declare
it inside app components so somewhere here I
899.28 -> can place the styles for my alternative header
right and if I save it those styles were applied
907.32 -> so let me close this and let's move forward to the
next feature so imagine that we have to we want
916.08 -> to implement the same thing but for our widget
content so let's get started to do that so I would
923.82 -> need to duplicate this input right and just maybe
rename it so I say that this is content template
932.28 -> and then I have to create a similar construction
for a video template as well so I create NG
941.34 -> container where I also apply the NG template
Outlet directive right and there I have to
950.04 -> create also the templates so let's create another
NG template like that and I say that this is the
957.48 -> default widget content like that and this engine
template should wrap this HTML so here we go
967.56 -> uh what I forgot I forgot to provide actually
values to the ntng template Outlet directive so
974.58 -> I say that it needs to take other content template
provided from user or it should have a fullback
983.58 -> that points to this engine template so here we go
then in order to provide the alternative content
990.36 -> view for this widget you probably uh go to the
app component you are going to create a new NG
998.22 -> template you are very excited that finally
we'll customize this component you start to
1004.16 -> bring some new alternative view but then you are
quickly realize that okay you need to render the
1012.86 -> temperature but where we will take this data
so here it is pretty much Clear yeah we get it
1019.64 -> from the state uh this is the property of this
component but here we don't actually have the X
1027.5 -> s to this data one of your suggestions could be
like okay we could get actually the reference
1035.06 -> to the weather widget component instance using
uh view child decorator right and once we get
1041.12 -> the reference we could simply read the state
property from the component and then render the
1048.86 -> value we need inside the alternative template
the solution would theoretically work and in
1055.88 -> practice it would also work but this solution
is quite terrible because imagine that you have
1062.78 -> not only one weather widget here but you have I
know dozens of them then you would need to get
1068.18 -> reference to all of them track if you properly
resolve States for each of this weather widget
1076.04 -> instances also you might have them implementation
of the component where the state is protected or
1083.9 -> private then even even if you get a reference
to it you will not be able to read this property
1090.44 -> because it is just protected yeah so this solution
isn't the best one and let me show you another one
1097.7 -> that works perfectly for that and this is where
NG template Outlet context property comes into
1105.14 -> the play and template context it is nothing
else as Chester data that is available for
1114.26 -> some particular angular template and in order
to provide this data to that template we have
1122.36 -> to use a special property of the NG template
Outlet directive and it is simply called NG
1129.44 -> template Outlet context and as I said it is just
the data which can be represented as object and
1137.3 -> we can say that for this template that can be
available a variable like temperature and their
1147.08 -> value for the temperature will be the data that
we will read from the state so something like that
1156.08 -> and of course you can provide multiple options
so you can provide actually anything you want
1162.44 -> um we can also do the following thing and
instead of providing variables one by one
1167.78 -> we can just simply provide uh the whole state
to it right so I can do something like that
1175.52 -> and provide just whole state and here in the
generic of the template ref we Define exactly
1183.44 -> the context so the list of variables that might
be available and here we can say that we provide
1189.68 -> the widget State for the content template right
so I can save it and then inside the alternative
1198.68 -> template right here by the way let's name it
like alt widget content here in order to read the
1207.68 -> variable I provided right here I have to use the
following syntax we Define the let like a variable
1215.72 -> then after the dash we Define the name of this
variable that will be eventually used inside the
1223.22 -> template yes so I can say that this is uh going
to be State and here inside the quote you have
1230.18 -> to specify to which exactly key of the template
context object you want to get a reference in my
1238.4 -> case I want to read this key State yeah so I can
copy it and provide it between the quotes and in
1247.16 -> such a way I will get a reference to this
value also if you have ever worked before
1253.52 -> with templates and context you must probably
encounter the very special key called implicit
1260.84 -> like that and this implicit key means that it
is default value of this context which means
1268.52 -> that you don't need to specify it explicitly like
we did or right here inside the chords and we can
1275.66 -> and uh leave it just like that and the value with
the key explicit so means the state in our case
1283.76 -> it will be automatically assigned to this state
variable and now I'm ready to use this variable
1291.56 -> inside my template so I could do something like
the following so I can use the state then I could
1301.28 -> read the data from it and I would like to read
temperature right here we go then if you don't
1306.98 -> mind I will do the similar thing for the rest
of the properties like Sky condition and then
1315.74 -> the same thing also for the wind so here we go and
now I can provide this alternative widget content
1324.08 -> to the weather widget component likewise I did
it for that template header right but this time
1332.12 -> I have to use the input content template late and
provide it as it is now if I save it look it works
1341.66 -> perfectly and it properly reads the data that we
provided for their context yeah so we we will read
1350.42 -> the real data Pro from the widget State because
we provided it as a context right here and this
1359.66 -> is really cool and powerful thing all right I hope
you are still with me and I hope you enjoyed this
1365.96 -> video and if so it is a great time to subscribe to
my YouTube channel if you didn't do it yet and hit
1371.78 -> thumbs up to this video because it will motivate
me to create more videos like that but now let's
1378.92 -> move forward and let's also customize this action
buttons yeah and provide the alternative view for
1387.86 -> this part as well so I will go to the weather
widget and here I'm going to implement pretty
1393.74 -> much the same thing like I did for the previous
two containers but this time it's going to be
1400.76 -> the action template right and uh where it is are
here I have to create a new engine container that
1410.66 -> also has NG template Outlet directive attached and
here we will provide the content template right or
1419.96 -> their default widget action and we have to create
this template right we already know how to do that
1428.18 -> we have to create NG template like that and place
those two buttons inside and also we have to give
1438.68 -> some name for this energy template here we go
done then let's get back to the app component
1446.12 -> and create them alternative view for this section
as well so it's going to be a new Android template
1454.64 -> and this time here inside I want to render not
just HTML but I want to render the component and
1463.1 -> we can't do that actually so let's generate one
I just run the following command or right here
1470.18 -> it will generate a component for me that I can
immediately import into my app component so it is
1477.08 -> a weather custom action component and then I can
also use it like this right then of course I would
1486.2 -> like to apply this new template to the weather
widget so let's do it right now here we go let's
1497.18 -> save it and you can see that my new component has
been rendered inside and now let's jump to this
1504.08 -> new component and what I actually want to have
right here is just the one single button that
1512.24 -> reloads the widget data and immediately copies
it so basically it it has to merge two actions
1521.48 -> we had before but perform it in one click
so the text will be like reload and copy and
1530.06 -> here is the question we have to somehow trigger
actions from them with weather widget component
1541.28 -> you might think that okay this template uh where
it is uh here we go this template will be rendered
1551 -> inside the weather widget component right so
it will be rendered right here so theoretically
1559.88 -> we could try to inject the parent weather widget
component into weather custom action component
1571.1 -> so we could do uh something like weather widget
and then inject and inject the weather widget
1579.08 -> component and from here uh we have to create them
click listener like that and then inside this on
1590 -> click Handler we could do something like weather
widget then we get access to actions right and
1599.36 -> then we can what we have to do first reload right
and then immediately after that we copy data so
1608.6 -> you would do something like that but if you have
a look at the console you can see that we have an
1616.7 -> error that there is no provider for the weather
widget component this problem appears because the
1623.72 -> apparent injector of the component that is created
inside the embedded view like we have right now
1632.18 -> the parent injector of this component will point
out to the component where this component has
1640.16 -> been declared and not where it is eventually
rendered so the parent injector for the weather
1647.42 -> custom action component is the injector of the
app component and not the one from the weather
1656 -> widget component so when the weather custom action
component tries to resolve their apparent weather
1663.08 -> widget component it does the following thing it
first of all checks its own injector if there is
1669.68 -> provider for the weather widget component it finds
nothing because there is no provider and then it
1676.88 -> goes to the parent injector and tries to resolve
it there but in this case the parent injector
1684.74 -> points to app component injector and app component
injector also doesn't have any provider for
1693.26 -> um for the weather widget component and then
angular calls uh towards the whole node injector
1700.1 -> hierarchy then it checks the environment injector
hierarchy finds nothing and then we see this error
1706.46 -> this process I actually described very well in
the dedicated video about dependency injections
1712.4 -> so if it is not very clear what I'm talking about
right now I would recommend you to check out that
1718.28 -> video as well but yeah how we can solve this
issue so we can actually explicitly provide the
1726.98 -> which injector needs to be used as a parent
for the components inside the embedded View
1733.34 -> and we can provide it as a property for the NG
template Outlet directive so actually we could do
1741.26 -> the following thing we can provide NG template
Outlet injector and this feature available by
1749.24 -> the way since angular 14 so make sure that you
use angular 14 and above in order to apply this
1754.94 -> feature and here you can provide any injector
you want you can create another one if you need
1761.66 -> but what you actually want to do is to reuse
the current injector from the weather widget
1767.84 -> and provide it as a parent injector for for the
components inside this embedded view so let's
1776.54 -> um create injector property and then inject
inject injector so here we go and then I can
1784.82 -> use this property as an argument for this input
so like that and if I save it you can see that the
1792.86 -> error disappeared and if I click reload and copy
those actions will be executed because the weather
1801.2 -> a custom action could properly inject the widget
component and Trigger its actions all right and
1810.56 -> now let's very quickly recap all the key points we
have learned in this quite a long video so if you
1818.54 -> want to declaratively render some angular template
you have to use NG template Outlet directive and
1825.86 -> you can provide some reference to the template
that needs to be eventually rendered you can
1832.16 -> provide templates conditionally depending of which
template needs to be rendered and it allows you to
1839.36 -> easily customize the view of your component
and make it very flexible and extensible if
1847.76 -> you need to provide some data for your templates
you can use them template context and pro and use
1856.82 -> the property NG template Outlet context for it
here as a value you can provide any object you
1865.04 -> want and this object will be available inside the
10 plate via these syntax that let Dash and then
1876.02 -> any name of the variable and then you can specify
some exact key that needs to be assigned to this
1884.78 -> template variable if you have a key explicit in
this context object it will be the default value
1892.7 -> for it the next important point is that if you
render inside your template some component then
1900.98 -> by default the parent injector for this component
will be point to them injector of the component
1909.14 -> where this component where this template is
declared and not where it is rendered so that's
1916.52 -> why you have to explicitly provide where it is
then injector for them for the angular template
1925.76 -> and this injector will be eventually used as
a parent for the components that were rendered
1933.26 -> inside this embedded View and now just a few
words about the limitations of this approach
1939.02 -> and some so to say downsides so the first
limitation is that templates here they always
1947.66 -> have any type they cannot be easily inferred
at least there is no official way to do that
1955.4 -> at this point in time where when I record this
video maybe in the future it will be fixed but
1962.3 -> uh those templates they are not strict so there
is a chance of typo and some mistakes in your
1970.64 -> templates yeah so this is something you have to
care about yes there are some workarounds uh but
1977.84 -> I will drop it for this video and I will rather
post it as a separate front-end snack so subscribe
1984.8 -> to my social media profiles to not miss it and
overall you will get a lot of another useful
1991.34 -> information from my uh short tips and tricks this
is the first kind of limitation another thing I
1998.96 -> would like to highlight it is not a limitation
but rather downside it is their templates syntax
2006.94 -> yeah I know a lot of developers do not like it
I also cannot say that I'm a fan of this syntax
2014.08 -> but yeah we don't have any other Alternatives
so we have to use that I also don't like the
2023.14 -> um this magical keyword like implicit for
the default value so it is not obvious to
2031.9 -> me I think so I think it could be improved but
this is something you know that we just have
2038.38 -> to accept and uh use it all right guys that's
it for today I hope this video was useful and
2045.4 -> if so please don't forget to share it with your
colleagues and friends and don't forget to check
2050.32 -> out my Advanced angular video courses links to
them you will find in the video description as
2056.5 -> well as some coupon codes also please share
your thoughts in the comment section for this
2061.6 -> video please share with me what do you think
about this feature have you ever used that if
2067.18 -> so in which use cases maybe I forgot to mention
something I think it would be very interesting
2072.76 -> discussion in the comments otherwise I wish you
proactive uh wait a second this video is the
2080.08 -> last in the year two 2022 so I wish you all the
best and big success in the next upcoming 2023
2091.54 -> so stay safe um I hope this year will be uh
better definitely better than the previous
2098.62 -> one so uh stay healthy stay safe and see you next
year in the new video [Music] thank you [Music]
Source: https://www.youtube.com/watch?v=vfPVdJ2oQlM