Angular state management with NGRX | NGRX tutorial for beginner | Angular project with NGRX state |

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone welcome back to our channel so today I'm here again to teach you another interesting topic in angular so looking at the video title you have already guessed that like today we are learning this topic which is ngrx store in angular so now you will be thinking that why I choose this topic so basically what I thought that easy topics of angular can be easily covered if you go on YouTube or do some little bit of Google also then you can easily learn the topics of angular quite easily and also thanks to our new website of angular version 17 angular def from there you can go ahead and you can learn lot of interesting topics like how angular actually works and whatnot so I thought let's choose a topic which is like quite confusing and it is very much important as well at the same time so the first topic what it came into my mind is ngrx State Management so ngx is something which is widely used in Enterprise level application to maintain their state also recently I have created a YouTube poll if you see here that I have asked a question how many of you think that ngrx is difficult and the number was quite amazing that 42% said that yes it is difficult and 46 were saying that they haven't even used it and this is because that they don't know the power of the state how the ngr EXP maintained the state so that is the whole and sole reason that today I'm here with this interesting topic to teach you so I promise after watching this video that uh your understanding for ngrx will be very clear and you don't need to go anywhere else to learn this topic again so let's first understand that why we need Ng RX reactive state for angular so it is not always that if the company is asking you in the interview that what is ngrx and then only you should go and learn it no that should not be the case if you're a good angular developer then you should be knowing that when and how to use the State Management in your application so this is what we have here on this website nx. where you can actually click on get started to learn a lot about it okay so we will be discussing everything about how to use this ngrx tore how to use them like how do we install them in your angular application and start creating your state so now let's take a use case of this application what we have in front of us that we have to create a add to card feature and now here if you see that here I have a cart component here in the header where it is showing the number of item in the cart okay so whenever I'm clicking on this button right what happens it takes this product goes here and tells the count of the application how much the count like we have it in the card okay so what happens right so from here we are changing the state suppose if I clicked one more item so this becomes from three this becomes four and now ALS so once you click on this uh like icon like card button then what you will do right you will redirect to a page where you will have the list of data here okay like what are the items you have selected from the product list page and also you will see the state of this price as well like whenever you click on the product right so it will add and update your price accordingly okay which means that's how you need to maintain your application like this is a different component this is header component this is product list component and this one is your cart component okay okay so in these three pages you need to maintain your data and to handle this kind of a data it is quite hard for angular to do so either if you have heard that how to share a data with unrelated components so we either go with rxjs behavior subject observables uh where if you look at this example right it will be quite easy to do to create an observable store and pass in the data but let's imagine if your component is growing and now you have a Enterprise level application where you need to maintain the global state it will become a bottle like for you guys to do things in the term of the observables like you need to do a lot of coding there you need to maintain your stores and do whatnot okay so how how ngrx is here to help us okay so now we are making use of ngrx to do the similar job what an observable can do but in a very efficient way okay so now let's first understand this particular diagram the how the life cycle of the ngrx is in front of us so the main thing what we have is the store okay the the store where we maintain the application state so it's nothing but your app State okay so in this app State you will be maintaining your data okay the data of your complete application and here two things which comes in picture that the this guy which is an action okay now let me take a one more very small and easy example so that things can go like let's go from basic to intermediate and then we'll go to advance so now let's take an example of a counter application okay so now here I have a account here and I have a two buttons here increment and I have a decrement okay and I have something called as reset okay so with this three button whenever I press this I want to change the state from one to two as for that once you click on button the state will get changed okay whenever you press increment increment it will increase the state of that if you press decrement the value will get decreased and if you click on reset this state will become zero okay so something like that we need to achieve it by using uh ngrx okay so now let's see how this architecture comes in action so now the first thing first right as I as I told you right we need to create some actions okay so in the ngrx we will create some actions okay for example what will be our actions our actions can be increment okay to increase the state uh decrement like to decrease the value of it and then we have a reset okay so these three actions I have so similarly I have to create actions for it so that based on the action what will happen your reducer will act okay so your reducer is nothing but will be there in your architecture to do some manipulation so this reducer will store all your uh State values okay and based on this reducer what reducer does is reducer perform some logic based on the action what it got okay so for example if you say that increment please increment the value so what this reducer will do this will take your previous state okay and based on previous state it will do some calculation and here the calculation is that I want the previous state plus I need to add one extra okay because we are doing increment okay so this will increase the state by one and once it increase right it will send it to your store okay so now this will have your the store will be updated with the with all the latest information of your incremented data in the similar fashion let's take for the decrement also it will do something similar okay so now if the user say decrement then what will happen the action will trigger this right the action will trigger now the reducer will take the previous State and based on the previous state it will minus one data because we are doing a decrement and once the data is decrement now again it will go to your store it will get stored in this store here okay what we have created initially now what happens in the reset reset is quite straightforward okay what will you do whenever you click on reset based on whatever the previous value was please make that value to zero because the counter starts from zero okay so this is how we will try to handle the data or you can say state of the application with ngrx okay okay now this is not done okay so now we have completed the this part of the architecture where we have action where we have reducers so now let's talk about the most important this side okay so what will this side will do okay for example now you have a component to view okay so now you have a component where you want to display your data correct you display your counter okay so what we will do right suppose your want to display that in an HTML and in the HTML uh you have something like this where you are displaying count and like this one correct which means you want to select your data from the store yes or no correct so you want to select your data so what you will do you will create a selector okay you will create a selector and this selector will uh what it will do it will select the value from the store okay it will go in the store he will say hey do you have the selector for the account he will say yes I have okay then selector will fetch it and go in the component and display it so in the component you have the HTML right so in the HTML file in the HTML file it will show the count as one because it was there as one in the store so the store will pass data to selector and the selector will select that particular slice and send it to your component and your component will view that view that data okay it will help you to display that data in the HTML okay now if you see this guy okay so this is also clear now let's talk about this guy so what happens right so in your component. HTML you will have the two buttons as well correct so now we are actually displaying the count okay so we have the count here okay we have the count as one at the moment then you have a button one and you have a button two and all these are part of your component okay so from the component right this is a button which means it will have a action it will trigger some action and this will also trigger some action So based on the click right the component is sending the action okay so this will what do this will dispatch this will dispatch some action okay and based on action it will the reducer will react based on the reactivity it will go and store the data in the store and based on whatever data you have in the store whenever the component selects the data the selector will help you to so you will select the data in the component and this is how the selector will give you the data whatever it is there inside the store and this is how the life cycle of an ngrx application goes on okay that's how if you see this arrows right if you see this Arrow okay let me show it again so that's how it goes right so component reducer then the store then selector and then again component so that's how these arrows are going okay yes or no so this is what the basic fundamental of an ngrx application and let me tell you that we are just covering the basic of ngrx that's why I'm not going this part yet okay this part I will cover it in a separate video where I'll talk about the advanced uh way to handle your data whenever the API calls are involved okay so first of all let's see how do we maintain the data in the application let's take an example right now we have a very good example in front of us let's let's start coding and let's see how we can make this counter in angular by using uh ngrx so now let's start the coding by actually creating uh a new project so what I'll do I will not go with ngu all those command because I've already created a boilerplate code and this already has angular material Tailwind already installed everything so what I will do I will go on my GitHub and I'll just clone this project run the command get clone and you can paste this URL and hit enter so now I'll just go ahead and rename the project from boiler to ngrx store YT okay let's hit enter and let's open up this inside a terminal I want to use vs code so let's do code Dot and I can see that my application is ready which is already running on angular version 17 as you can see here now all I need to do is just do npm install and we are good to go now once you hit npm install it will take some time as usual but it will be quite faster if you do with NG new and all that select the option so I thought better let's create a boiler plate code and put it on the GitHub whenever I need to start with a new project I can clone it from there now I can see the project is ready let's do NG Surf and let's see how things looks on the UI the compiler is so fast because of angular 17 for sure so now it is running on 420 let's go on the browser and let's open up the port 420 and yes this is how the template looks like for your angular material Tailwind okay all right so let's go ahead and create our first component so for that let's open up your new terminal and in that we will hit the command NG GC and the name of the component which is counter so as you can see the counter component got created and now I have to use it in the app component. HTML so that I can render it so what I'll do go in the component.ts file and you need to import it here so you'll say counter component because we are using Standalone component that's why and now you need to make use of that here somewhere here so now what I will do correct we have this hero section which is the center part of the application this one I don't need this one so let me remove that unnecessary things so we can remove this and we can also change the title from the nav bar uh we can change it to ngrx okay save the changes and now here we can make use of the selector app hyphen counter and this should be like we should be able to see the changes now let's go here and everything is compiled successful okay let's go in the Chrome and I should be able to see somewhere here but it is not showing it's fine let's go ahead and add some CSS or HTML to this guy so as we are using tailb CSS so let me copy paste my code snippet what I had already for the counter so this is how the counter uh UI will look like that it will have a title here on the app counter app then it will have the counter number which I want to display and just below that I have created two buttons which is the increment decrement and reset let's save the changes and let's go back on the UI to see how things looks like okay now it is not showing let me I don't know why let's let's go in the compiler and try to recompile your code again okay let's do NG server again so it's building the application let's go back and yeah so now I able to see that I think there is some some caching issue happened because we are using V so it actually cash your build sometime so you need to clear it so to clear that cash so you need to again uh do the NG serve so now it is fine so that's how we have this application where we can do increment decrement and reset okay so now what I will do right so first let's start see we can do it directly via the local state of the component but for example you want to display it in some another component then how you will do so for that I will be showing it with ngrx okay so now to do the ngrx thing first thing first you need to install the ngrx package so how do we install it again go on the official do and they will definitely give you some installation guide so here you can see there is an installation guide copy this okay so once the command is copied go into your terminal and paste it so NG add at theate nx/ store so now it will ask you to install I say yes and it will install the packages um should take less than 10 seconds I guess let's see yeah it's done so now to validate it you can go in the package.json and this should reflect the changes somewhere here the NG okay so now it is added successfully okay so let me tell you the way how you should proceed if you're trying to use uh ngrx into your Global like you're doing State Management with ngrx so first thing first what you'll do right you will first create your app State application state so to do that right let me create a folder so the folder name I will give it as States okay and inside the state you can create a new file and the file name will be app. state dots okay so now I will tell you about this file why I have added it but yeah like tell you on the later stage of the video so the first thing what I need to do right first I need to create the actions correct so now if you see in the UI I have three actions to do so if you remember uh when I was explaining you that installation things like how things will work and all that remember the diagram what I was showing let me open up that diagram first and over here this is what I was explaining so first thing we need to create the actions okay in the ngrx so to create it we'll go here and and we are creating a state for counter so I'll give the folder name as counter okay and in the counter I will create the first file counter. action. TS okay so the file is created so now in the action what I need to do I need to create actions correct so what for creating the action I need something from the ngrx store so let's import ngrx store if I say you want to create action what you should import I should import create action easy right so now I'm importing create action and this will help me to uh register all my actions what I will be doing so I need to do that one by one so first let's create our first action by saying export const give the name of your action for me it is increment okay and now I will say Okay increment is my action and let's give it a type okay and this should be unique so let me open up this bracket and inside that we will give a unique type to it and this is for counter component so counter component okay there is always a way how you should do it so this is the way what ngrx has recommended for us to do so that's what I I'm doing here so that's what we have and give it the name of Your Action which is increment okay so this should be unique and now let's go for the decrement and reset so I'll copy paste for both of them all I need to do just change the name to decrement and this will also I will change to decrement okay so decrement has been done again this is for counter component for decrement action and I think there is some issue with the spelling so let me change it okay and now this should be changed to reset so the third action is reset again this let's change it to now I can say that my action is ready see how easy I will make things easy for you guys do not worry so now the action is done okay so now my actions are registered in my store okay what is the next step so whenever there is some action the reducer will it will go to the reducer to do some manipulation correct so to do the manipulation so let's create a reducer so to create reducer again I will create a file counter. reducer reducer dots okay now again export export what I want to create a counter state so let me create that state here so export interface okay counter State because what this guy is doing so this guy is maintaining your state and it is doing some manipulation based on that so that's what I created a counter State here and let's give it a name let's create a name that I want to maintain something called as count and whose data type is a number okay so that's what I have created first so I have created a counter State okay and now what I need to do right I need to initialize my state right so let me initialize my state Again by saying export const initial counter state and inside that this is of type my counter State what I just created on the top and based on this interface I need to implement so the state will be count sorry oh this should be equal to and now we need to see here that initial count is zero okay so this is my interface of counter State and I'm implementing it here like this is the type of my initial counter State and I'm assigning the value to it as zero okay if this is clear right so now I can see my reducer is maintaining my initial State okay now based based on some action right my initial state will get changed like if I increment then this count should be one if I say decrement then again this count should become zero something like that yes or no now to create a reducer right what you will import you will again import create reducer let me import that so you'll say import from this is again coming from ngrx ngrx store and you want to create reducer so import the create red so now reducer is correct now let's create our own reducer because we are creating a reducer for a counter so let's give it a good name so I'll say export const counter reducer so let's give it a name okay counter reducer so again this is spelling mistake so c o u n t e r reducer okay I'm very bad with the spellings guys I'm so sorry okay so this is counter reducers and we want to create so again we'll say create reducer okay and inside this inside this create reducer what it requires the first thing it requires the initial state which we have already assigned on the top so I will assign this value initial counter State okay which is this zero all right and now as we know that we have events being triggered okay so now I need to register all the events inside my reducer so that my reducer will listen to those event okay so what I will say here right I can say on okay again this is coming from ngrx store on inside that you can say that okay what action you will listening so I'm saying increment so this is see uh which I have created from the action right so this is imported from there this action okay on the top it is imported by default so increment so whenever there is an increment then it will do something with the state so I will say State okay and now what this guy will do so we need to return the updated state so now what it will do it will take the existing state which means as I told you WR the previous state okay and based on the previous state what you have to do you have to update your count what will be the count your count is nothing but your state do count which is zero at the moment can you please add one to it one means I'm incrementing the value okay so whenever there is an increment your state will get updated correct and and how I'm updating the state I'm saying that based on the previous state please in add extra one so that I'm updating the state from 0 to one when there is one click okay s in the similar way I will register it for rest of the two action which is decrement okay decrement again see UT on the top and in the decrement what you will do it will similar right just from plus this becomes minus okay but now there is a catch for this one that whenever you are saying uh for reset reset there is no cash to be honest anybody can guess now that what I need to do so for a decrement you will just say that okay whatever the previous state was okay I don't care can you make this count directly zero I don't need to do any manipulation because I'm doing a reset so the reset should make this count as zero okay and in this way that your action and reducers are ready okay so now whenever the action will happen the reducer will uh take your previous state and do some manipulation and it will update the to it for you all right so now I'm happy to tell that our action and reducers are ready so now what is the third thing we need to do we have to make a selector yes or no but before that let me first uh make the changes here this should be reset not decrement okay so that's what so now we have all three actions imported and now based on the actions we are doing the job now to create the selector let's see what we need to do now if you remember that what I was telling you that this action reducer and this reducer will send the data to the global store basically your app State remember and you remember that Ive also created this file app.st state. TS okay so now we will make use of this file to create the global state or I can say to create the application state so what I will say I'll say export interface okay App State and inside this app State what is my first state I want to maintain I want to maintain it for the counter so I am saying that hey please register a counter state which I have created see so this is what I have created and this is in the reducer it is it is there in the reducer so I have imported it so this is this is my first Global state or you can say application state which I have registered okay now if this is done if you remember now we have a global store ready now which means action will send to reducer reducer will send to store now I have a store also now from store I want to take it to the selector so now I need to add a selector okay so now till here we are done so now let's see what is the selector job so in the counter folder let's create counter. selector dots file okay and the selector uh let's create the file here we'll say export const select count select the counter State that's it now if this is done now we have to update the counter state so what I will say Okay state is of type app state which we are which we have created here so I'm importing it here on the top so whatever the state you have can you please select it for counter okay so that's what I'm trying to tell him so can you please return whatever the counter state is to the counter State like select counter State I will say yes why not I'll say state do counter State now you will have a question why sh you did this only like for example now you're creating a state for cart component like add to card component right I was telling so what I will add I will add it something like this so I will say that now I want to maintain for cart okay now I will give the name as counter or sorry the cart cart State something like this okay so in future this will grow currently we are only showing for one so it's fine maybe in the next video where I will take you the inter I will take you to the intermediate level of ngrx so at that time maybe I'll will demonstrate an example of this card C state of this card State sorry not the counter card State okay now let's see in the selector so now that's what I said that okay please App State whatever the data you have in the counter send it to the selector okay so now this has been updated now whenever my components so now the job of component wants to select some data okay I want to expose the data right so how will I expose the data let me show you that so to expose the data will say export con select count okay select count so this is the guy where we will add the create selector okay create selector see imported on the top as and now in this selector this guy needs two things can you please specify the selector for me I will say yes yes it is on the top I have created so select counter state so from this counter state do one thing okay you will have a state maintain so can you take so from your state can you please send the count to the component he will say yes why not okay so that's what it is doing so now here I have the whole counter state but from the whole counter state do you need the whole counter State no right you need only the count okay so I want to only select a slice of a data okay from a bigger data the component only requires the count that's it so because this counts I will be displaying it somewhere here correct so your component requires your count number to display it here yes or no and based on that that's what this selector is doing so your selector is taking from this bigger slice he's taking the smaller slice which he requires so that's what this create selector does okay specify the select counter state which has all the data and from this data can you please send the required data which I need to display on the UI that's it okay so once your these three files are created now you guys are ready to go and use them in your component okay but before that as you have created a created a state so you need to register it in the appconfig dots okay so if you guys are using I don't know maybe if you guys are an older version of angular like 14 15 so you have to register that in the module and maybe I can show you the way how to do that but let me show you how to do things in angular version 17 so if you haven't even updated your application to 17 please do it guys it has a tons of feature for us okay now here you can see this is already added once you install uh your I did the command right to install the package so this by default adds this guy which is provide store from ngrx okay now just below this slide we want to provide state so I will say provide State okay and in this provide State I need to specify two things first the feature name okay what which one are you actually looking for so I'm saying that the name of that is counter okay okay so for this counter what is your reducer for this state what is your reducer you need to specify the reducer then only I can do the manipulation so okay you can take all my data from this reducer which I will just name it okay so reducer and give you the reducer name what you have created so the reducer name here is counter reducer okay so let's go here again and call that because we have exported it so we can import it again so counter reduce and now once you import it right now I can say that the configuration is also done and you are good to go and you can use this in your application okay so this is what the initial stage is so I know you guys will see that this is a lot of boiler plate code that I need to add to achieve something very small but trust me guys when the application Grows Right your state of application will be very hard to maintain if you don't have something centralized way what ngrx provide okay currently I cannot demonstrate that because I have a very smaller application for you to Showcase so that's why okay but this is the this is what the fundamental I want to just demonstrate like how we can use it in your application so now it is job of your component to display the account right which is currently it is zero because it is static okay now what I will do I will create a variable whose name is count and this is an observable okay so this is an observable of type number okay and now I will take the Constructor and in the Constructor let's inject the store okay and the store is coming from ngrx / store okay and inside that you need to specify okay which store are you looking for I'm saying that App State the global State what I have created he will say okay I have injected that successfully now let's initialize your behavior subject or you can say sorry the observable what you have just created on the top so I will say okay I will say this do store do select see if you see this right in this component I'm saying please select from the selector please select my state I will say okay sure sure so now this do select please create can you please send the map function for it like which you have created remember we have created a function here which is exportable okay the select count this is what we need to place it here in the select so now I will say select the count so once you add this right if I H on this can you see what is the type of this this is type of observable of number okay so now what I can do right I can make use of async pipe so let me import async pipe and go in the HTML and over here I can update this by saying count and I'll make use of async pipe here let's save the changes let's see if the compilation is Success yes and now if you go here that you can see a count here which is zero okay now for example why is it zero why not it is 10 because our initial State what we have created in the reducer was Zero what if I make this 100 and save the changes let's see and you see the initial State updates to 100 now correct now let's see the magic now let's again make this to zero now as you remember right now we have achieved the we are able to connect everything we are able to connect all the dots from component to action reducer store selector everything is there now what is one thing missing here that this part where I need to dispatch some action from component okay so to dispatch some action what you'll do right so now we have two actions button here like three action button basically which is the first one this so I will say click okay on click you want to do increment same thing I need to do for this one again on click I want to do decrement and the last button which is reset again whenever someone clicks I want to do reset okay now we'll have to create all the necessary method what we have on the UI so first is increment so second one is decrement which I have created and the last but not the least is the reset so now I have these three function created now whenever someone is clicking this function I want to dispatch a event and from where this dispat dispatch is coming again coming from ngrx store which I can say this do store do dispatch see how easy it is dispatch can you please provide your action which you want to dispatch I will say yes yes I have created three actions right I want to dispatch action number one which is increment uh remember this one you should not call your own method okay increment and that's how it is so this is your action same same thing you need to do for okay again if you are getting confused this increment I'm importing here also see State SLC counter slash counter. action so this is coming from our action which is increment which we have created here please don't get confused if you're still getting confused please let me know in the comment section okay so for this one again I will need to call the decrement so we have a decrement action again imported here and the last but not the least the reset so I can call the reset here and I did the mistake so reset okay that's one now save all the changes here so every everything is imported everything is in place uh compile is also success now let's see things in action now if I do this increment right see what happens okay this is not working don't know why see it is not working let me check what is the issue all right so guys I faced a very weird issue I don't let me share that with you I did nothing trust me I did nothing I just did uh stop the application by here contrl C I did contrl C and then I restarted the application and now if you see that it is working can you see it's working fine I don't know maybe it's because of the build is getting cashed already because of weat new we and that's how the behavior of we is so I need to disable that for sure okay so now if you see that uh now I'm able to see increment decrement and I can do reset as well okay now a lot of you can see Shashi this what is a big deal in this that this you can you could have done it directly here in this in this particular component but that's not the thing what I'm trying to Showcase here see the magic of this increment decrement like for example this data which you see here if you want to show it over somewhere over here in the header component okay so this is a different component and and this is a different comp now let me show you that how we can achieve it so now all you need to do is uh you just need to copy this okay uh so that I should not create the variable again I'll go in the component here okay import everything all right so now this is how it is now I'm inside a different component which is app component okay and now inside this I can directly use this counter somewhere here near the home I can create a button or maybe somewhere here I can display it now again I'll do something similar which is Count make use of asyn pipe again this can throw error I don't know for that let me check if Asing pipe okay we have a common module so we don't need to import it so we can directly use Asing pipe here let's save all the changes and let's see things in action again now if I increment right can you see this my data is maintained here as well as my data is also getting displayed so this is what the reactivity I was talking about that once you update your state in the one component it will also get reflected in the another component okay and if you want to achieve it you have to create subject Behavior subject do do that subscribe and all that but with ngi direct store you can make things all centralized and and that's how that's what simple it is to be honest okay so that's how you maintain a global State inside your angular application by using ngrx again if you want to play around with this application I will be pushing it on the GitHub and I will provide the GitHub Link in the description so you can take a look and you can start using or you can start creating your application based on this ngrx State Management all right guys so that's it from this today's video uh if you guys need uh some more example about like if you want me to create a at to Card application by using ngrx store then do let me know that in the comment section uh if I see 10 plus comment right so I will definitely go ahead and create that video for you so that things can become more clear for you guys all right also if you have loved my content then please give it a thumbs up consider subscribing to my channel and also share this video with your friends so that they can also learn this coolest State Management things in angular also guys if you want to connect with me on all my Social Links so I provide all the links in the description so you can go ahead in my description and you can follow me on all my social networks I will be happy to connect with you guys and if anyone from you are interested in in writing blogs then do connect with me so that I can assign you a role for let in let's program blog where you can write articles and you can share it with your friends so that they can also learn new new things what you have learned by writing these articles all right and also if you want to uh like uh have some request like we video where you want to learn something new whether it is angular react net nodejs then please do let me know in the comment section I will happy to see see those comments and start working on that video for you guys to make things easy for you all right so that's it then enjoy your rest of your day keep learning keep coding and see you in the next video
Info
Channel: Let's Program
Views: 7,889
Rating: undefined out of 5
Keywords: AngularTutorial, NGRXGuide, StateManagement, AngularBeginners, LearnNGRX, AngularDevelopment, WebDevelopment, CodingTutorial, JavaScriptFrameworks, AngularProjects, FrontEndDevelopment, AngularJS, ProgrammingBasics, TechEducation, SoftwareDevelopment, CodeNewbie, LearnToCode, AngularNGRX, AngularState, DeveloperTutorial, WebDev, AngularTips, TechTutorial, CodingForBeginners, WebProgramming, TechLearning, AngularFramework, CodingSkills, WebAppDevelopment, AngularCommunity
Id: a3_GW3RBqn0
Channel Id: undefined
Length: 34min 47sec (2087 seconds)
Published: Mon Dec 25 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.