Hi Friends In Angular 16, an exciting new
feature has been introduced. Signals. Signals are reactive primitives
that offers granular tracking of state changes within the application. Signals was introduced in Angular
16 and became stable in Angular 17. In this video I am going to explain some of
the key concepts in Signals, benefits of using signals and then I am going to show you how to
implement signals in an angular application. Before that, I request you to subscribe
to this channel and support me. Ok. Let's start. To understand about signals, we
need to know about three reactive primitives. Writable Signals,
Computed Signals and Effects. Writable signals are a specific type of signal in Angular that allow you to
modify their value directly. Let me explain this using an example. I have created this simple application. In which, I have a button and a count value. On clicking this button, this
count value will increase. For that, I have created a count
variable and on clicking this button, I am calling a function and inside this
function, I am just increasing this value. Now, let's change this to a writable signal. How can we change this? We just need to use the signal constructor.
We can also pass the initial value. Like this. Now this is a signal. And so, we cannot directly
increment it. It will throw error. If I console log this, we can
see, this is a signal function. So, how can we access the value. We just need to call the function. Now, we can see the value. And so, you can ask me, to
fix this can we do like this. No, we cannot assign a
value to a signal like this. There are few inbuilt functions available
to change the value of a signal. If we need to just replace the
value, we can use the set function. Let me set the value as 7. Now, if I click the button, we can
see it is getting changed to 7. Similarly, instead of 7, if I give this dot count
plus one, we can see this is getting incremented. But according to angular documentation, we
have to use set to update a simple value. And, we can use update method to update a new
value of a signal depends on its previous value. So, let me use the update method. Update method accepts a function. Like this. We can see this is working as expected. So, we have seen how we can update simple values like a number. Let me show
you how we can update an array. Let me create a new signal having an
array as initial value. Initially, I have kept two elements in the array. Now, I need to add another array. For this use case, we have another method, mutate. Mutate accepts a function which
takes all the values as parameter and we can use the push method to add the
value and return all values. Like this. Now, if I put a console log, we
can see when I click the button, we can see the new value
has been added in the array. But, this will work only in angular 16.
This has been dropped in angular 17. Instead of mutate, we can use update itself. But, when we use update function, instead of push,
we need to use the spread operator. Like this. We can see, this is working. So, we have learnt about writable signals. Let's move to computed signals. Computed signals are essentially
values derived from other signals. Computed signals are read only. We cannot
directly set the values of computed signals. Let me show you an example. Let me create a new signal, length. And, another signal, breadth. Now, let me create a computed signal, area.
Which is going to be the product of both. Let me show this area instead of count. We can see, 800. Now, when I click the button, let me update
one of the signals. May be length to 30. Now, if I click the button, we can see 1200. That means, when one of the signals is changed, the computed signals is
automatically getting recalculated. That is about computed signals. We have one more concepts, effects. Signals are useful because they can notify
interested consumers when they change. And, an effect is an operation that runs
whenever one or more signal values change. Effects always run at least once. Like computed signals, effects keep
track of their dependencies dynamically. Let me show you how to create an effect. The good place to create an
effect is inside a constructor, because effect function
requires an injection context. So, inside constructor, let me create an effect.
Effect accepts a function. Inside that function, let me put a console log. Inside the
console log, let me use the count signal. Similarly, let me create another effect.
Now, let me use the colors signal. First, let me update only the count signal. Now, if I click the button, we can see
only the first effect is triggered. Let me comment this and update the colors signal. Now, we can see the second
effect is getting triggered. If I update both, we can see both
the effects will be triggered. If I just refresh the browser, we can see
these, because effect always run at least once. Effects will be used in many places. For example, if you want to log something when a
signal is changed, we can use effects. If we need to update the local storage when
a signal is changed, we can use effects. But, there are certain things we need to consider while using effects. We should not
update any signals inside effects, because it may trigger infinite circular updates
and trigger unnecessary change detection cycles. To avoid this, setting signals is
disallowed by default in effects. But we can enable that if it is really necessary. I will show you an use case shortly to
enable setting signals inside effects. Ok. We have learnt the important
concept in Signals. But, do you understand why we
really need to use signals? Let me explain that also using a simple example. Let me create a variable a equals to
10 and another variable b equals to 20. Now, let me create another variable
c, which is equal to a plus b. And, in ngOnInit, let me console log this c. After that, let me change the value of a to 50. Now, let me console log this c again. And so, we can see 30 and 30. This is because, the value of c was
calculated before the value of a was changed. And so, c has no idea whether the
value of a has been changed or not. There is no reactivity. Let me implement the same using signals. Ok, now we can see, the first console log is
printing 30 and the second one is printing 70, because now the signal c has been notified that
one of the dependent signals has been changed. And so, the value has been recalculated. This has reactivity. Hope you understood the use of signals. Now, let's see how signals are
useful in a real time application. I have created this add to cart application. Here, we can add fruits and
vegetables to the cart. And we can click this cart to see
the items in the cart. Also, I have implemented a mechanism to show the
points to be earned based on the cart value. I have added only limited features. For
example, I have added logic only to add to cart. There is no feature implemented to reduce
the quantities or to remove the item from cart. The reason is I want you to focus on
the signals implementation. Adding too many features may deviate us from the concept. Also, I have not implemented a perfect add to cart
design. For example, I have added some subjects, some @Input and @Output, etc. Definitely,
we can follow a better design to avoid this. But I have implemented this in such a way
that I can explain you the signals concept. Ok, first let me show you this
feature. When we click this cart, this cart is getting opened and on clicking
this close button, we can close this cart. Let me explain how I have implemented this. In cart service, I have created a behavior
subject which is having an initial value as false. In header component, on clicking this
cart icon I am calling a function, inside that I am changing the
value of the subject to true. Similarly, in the cart component, on clicking this
close button, I am changing the value to false. And in app component, I have injected the cart
service and in the template, I have kept the cart. And, I am toggling a class named open,
based on the behavior subject value. I have used the async pipe to resolve the subject. And in css, you can see I have placed the cart in fixed position away from the view
port and when the class is added, I am moving the cart inside the view port.
I have also used a transition effect. Ok, now let's see how we can
use signals to simplify this. First, in the cart service, I don't
want the behavior subject. Instead let me create a signal. Let me
keep the initial value as false. In the header component, let me remove this
and let me set the signal value as true. Similarly, let me set it as
false in the cart component. Finally, in the app component, I don't want the async pipe. I can
simply get the value of the signal. That's it. We can see it is working like before. But now, we don't need the behavior subject
to notify all the components. Ok. In the cart service, we can
see I have two more subjects. The refresh cart subject is to notify
the cart component whenever I add an item to cart. So that the cart will be refreshed. You can see, in add item component,
once an item is added to cart, I am calling the next function of this subject. And in the cart component ngOnInit,
I am subscribing to this subject and whenever there is a new value, I am
calling the refresh cart function. In this refresh cart function only, I am
having the logic to calculate total price, total quantities and the final
cart to display in the cart popup. You can see, if the item is already
in the cart I am just increasing the quantity or otherwise I am
adding the item into the cart. Also, I am maintaining the total value of the cart in the cart service. So that I can
use that to calculate the points. So, after the total value
is set in the cart service, I am triggering another subject refresh header. In the header component, I have
subscribed to this refresh header subject and whenever a new value is received,
I am calling the refresh points function. In this function, I have the
logic to calculate the points. Now, let's see how we can change
this implementation and use signals. So in cart service, let me
delete these 2 subjects. I don't want them because I am going to use signals. And, let me change this cart
and this totalValue to signals. In add item component, we don't want
to notify now. So, let me remove that. And in the cart component, we don't want
to subscribe. Let me remove that also. Similarly in the cart component, we don't want
to notify. And so, let me remove this line. And in the header component, we don't want to subscribe to the
subject. Let me remove that as well. As we have changed these cart
and total value to signals, in the cart component we need to change this. Now, we are getting an error.
This is because of typescript. We can fix this by adding a type in the
signal declaration in the cart service. And then, here we need to use the
set function to set the value. Ok, in the header component
we don't need this function. Instead, let's create this points as a
computed signal, so that whenever the total value signal is changed, this
will be automatically recalculated. And, when we change this to a signal, we
need to change in the template as well. This cart is also a signal now, and
so we need to change this as well. To add an item into an array,
we can use the mutate function. Like this. We can see one more error. We need to change this as well. Ok. No more errors. Let's test this. When I add some items to cart, we can
see the cart count is getting changed. But, if I open the cart, we cannot see any items. Also, this points is not getting updated. What could be the reason? The problem is in the cart component. Earlier, we used the subject to trigger
this refresh cart function. But now, this is not at all called. So how can we trigger this function. Here comes the use of effects. Let me create an effect inside the
constructor and let me call this function. That means, whenever my cart signal is changed,
I need to call this refresh cart function. But if I refresh this page, we can see an error. We cannot set a signal value inside
an effect or inside computed signal. We can see we are setting the total
value signal here. This is not allowed. But we know, this is not going to trigger any infinite change detection
cycles or impact anything. So for this scenario, we can use
the create effect options. Where we can set allow signal writes to true. Like this. Let's test this once. It is working as expected. Hope you understood how we can make
use of signals in our applications. If you like this video,
please hit the like button, subscribe to this channel and share this
video with your friends and colleagues. Post your valuable comments
in the comments section. I will be back with another
interesting concept soon. Thank you. Bye.