Standalone Components in Angular

import(`./subsection/subsection.module`).then( m => m.SubsectionModule ) } ]; The module would have to load all components, providers, and could even include it's own router. I always found this to be a lot of boilerplate code just to implement lazy loading. Now with a standalone component, we can make it simpler, which I love. First, let's create a simple routes that does not include lazy loading. Open up the app-routing.module.ts file: const routes: Routes = [ { path: 'view1', component: WrapperComponent }, { path: '**', redirectTo: 'view1' } ]; The first route is named view1, and points to WrapperComponent. I also added a catch all route, distinguished by the two asterisks in the path. The catch all route redirects to the view1. Now, open up app.component.html: Remove this and replace it with the router outlet: With this approach, we can remove the component import from the app.module.ts. Instead of this: imports: [ BrowserModule, AppRoutingModule, WrapperComponent ], We can just do this: imports: [ BrowserModule, AppRoutingModule ], Recompile the app, and load it in the browser: You can see the route in the browser at view1. Start typing to make sure it all works: All good to go; so, we've proved that the stand-alone components are working fine with the router. But, the use of the router here mirrors what we did in the main books, which did not investigate lazy loading at all. How do we set up lazy loading of the module? Back to the app-routing.module.ts and replace the view1 route with this: { path: `view1`, loadComponent: () => import(`./wrapper/wrapper.component`).then( m => m.WrapperComponent ) }, The syntax is very similar to the lazy loading segment I shared earlier. Instead of a loadChildren() method, we now use a loadComponent() method. The value is an arrow functions. The arrow function uses the import command to load in the component. The import returns, surprisingly, a promise. We resolve the promise with the then() method, and the result handler returns the component. You can re-run the app right now to see that it is continuing to work, but to see the real power of lazy loading, let's create another route and view. Let's create a new component: ng generate component view2 --standalone You'll see something like this: We're not going to implement a lot of functionality in the View2Component, only using it to link between the two respective views. Take a look at the default view2.component.ts: import { Component } from '@angular/core'; import { CommonModule } from '@angular/common'; @Component({ selector: 'app-view2', standalone: true, imports: [CommonModule], templateUrl: './view2.component.html', styleUrls: ['./view2.component.css'] }) export class View2Component { } To tell Angular to link between routes, we'll need to load in the RouterModule as part of the imports configuration: imports: [CommonModule, RouterModule], And don't forget the TypeScript import: import {RouterModule} from "@angular/router"; Open up view2.component.html. Replace all the contents with a link back to View1: Goto View1 For View2Component that's all we need. Let's go back to View1 which is powered by WrapperComponent. First, we'll need to tell it about the RouterModule in the component config imports: imports: [CommonModule, DisplayComponent, EditComponent, RouterModule], Don't forget the TypeScript import: import { RouterModule } from '@angular/router'; This is the same as what we did in the View2Component. We'll made a similar addition in the wrapper.component.html: Goto View2 I added a link to view2 in front of the other two components in the WrapperComponent. Now, open up the app-routing.module.ts. I'm going to show you the two cases, and how the browser interacts differently. First, with no lazy loading setup: const routes: Routes = [ { path: 'view1', component: WrapperComponent }, { path: 'view2', component: View2Component }, { path: '**', redirectTo: 'view1'} ]; Run the app, and take a look at the network console: Click in the browser between the two views and you'll notice nothing changes in the network tab. Everything is loaded all at once. Now, let's switch back to lazy loading in the app-routing.module.ts: const routes: Routes = [ { path: `view1`, loadComponent: () => import(`./wrapper/wrapper.component`).then( m => m.WrapperComponent ) }, { path: `view2`, loadComponent: () => import(`./view2/view2.component`).then( m => m.View2Component ) }, { path: '**', redirectTo: 'view1' } ]; We've already explored the view1 route and the catch all redirect route. This includes a view2 route, which loads the View2Component. Now reload the app in the browser and review the network tab: We load most of the same files. One thing you'll notice is that main.js is a lot smaller. And there is also a an additional js file loaded, which corresponds to the WrapperComponent. The end result is that we have less data loaded on the initial app load--which means your users are using the application much quicker. Click over to View2: I didn't clear out the network tab before clicking, but primarily you see View2Component loaded, but not until we clicked on the link to load that view. It is beyond the scope of this article to go into the benefits and specifics of lazy loading, but let's just say I love this use case for stand-alone components, because it is something that clearly removes a lot of boilerplate. Final Thoughts I learned a lot by exploring this post, and writing the chapter in my book. I hope you learned a lot reading it. I'm not sure how I feel about standalone components yet, but I do see them as a one way to make Angular applications easier to build, especially around lazy loading. I also see a lot of potential using them in libraries, where you want to optimize a component for reuse. If you've gotten this far, thank you for reading. Be sure to check out the bonus book from the Learn With Series on Angular 15 , which includes a more in depth version of this post with more samples including using services with standalone components, bootstrapping an application without using a module, and learning how to test stand alone components.

From: Jeffry Houser's Blog

What is a Typical Day for a Manager?

I was buried deep in some side thread in an on-line forum, and someone asked me what a typical day was like for me. Nowadays, I'm a leadership role, with team-mates who report to me, so my day. or week, or year is a lot different than what it used to be when I programed every day. Defining a typical day is pretty hard, since the day is very variable, but I thought I'd give it a shot. But, to get a full scope of my job, I can't stop at just a day. I'll start by looking at a typical day, but then I'm going to look at a typical sprint, and then a typical year. What is a Typical Day? I'm not sure I would call any day typical; unfortunately, but let's give it a shot. 8am – 10am I get into my home office somewhere between 8am and 9am. I'll sign in and start going through my Slack notifications. A lot of messages to me or my team can build up and I try to spend an hour or two in the morning clearing out my queue. For non-urgent requests from the past, I may have used the slack reminder feature to remind me tomorrow (or next week), to come back to this. I don't want to forget. These reminders show up in the morning, and I try to catch them and respond. These may be questions about our systems, or how they work. They could be some non-priority issues. It might be a casual conversation with someone else I didn't want to forget about. Note that email is not the primary means of communication in my current environment. Eventually I'll get around to checking email, but it is usually company related newsletters or meeting invites and is relatively easily cleaned. 10am -11am My meetings do not usually start before 10am, and some days are busier than others. My team does not have daily standups, but rather we do two in person standups per week, and Geekbot on the other days. Usually morning meetings are 1:1 discussion with someone. More details on those meetings when I talk about my sprint. 11am-12 noon Around 11:00 we do a team deploy to prod. Production deploys are not automated, I believe due to some type of compliance. The company institutes a stakeholder review step, and in most cases I am the stakeholder. I have to review all the tickets completed by the team and approve them to be pushed to production. Thankfully our Dev and QA deploys are entirely automated. 12 noon to 1 Between 12 and 1 I have lunch. Most days. Some days my lunch stop is 3 minutes, other times I can relax for the full hour. Often this time slot often overlaps with lunch and learn, town halls, or other educational team meetings. 1pm to 4pm After lunch, the meetings will start up again. Some meetings are planned and recurring, and I'll talk more about that in the sprint section. A lot of ad hoc meetings to fill the time. It might be a sidebar with product owners to clarify requirements. It might be with a subset of my engineering team to talk about some issue. It might be an introductory meeting with another engineering team to discuss a new initiative we'll work on together. It might be a team review meeting to discuss the latest spike and RFC that will define what the team will build for the next few weeks or months. 4pm My wife is a school teacher, so if the stars align I'll break for dinner when she gets home from work. This usually happens 2-3 times a week. 5pm-6pm Sometimes after dinner, I'll be done for the day. Other times I'll check back-in to work. Research Research In my time around meetings, some of it is research or education. Here are some of the things that may occur: Team members often ask me questions to come out of 1:1s, for example I spent a few hours researching the expense policy for external classes, corporate travel, or recent return to office guidelines. I'll also read and comment on new product briefs from our product team Sometimes I'm reading and commenting on research spike from other teams we work with, if that work is relevant to my team. Sometimes I'm reviewing management documents, such as guidelines on new procedures or other communications from upper management, and I have to figure out what is relevant to my team, and a way to communicate that. When the team was hiring, I'd be spending time at least once a week to review resumes and give feedback to our recruiter. Some of my time goes to team building activities. Team lunches, or other team building experiences such as escape rooms. Sometimes I'm working with a designer planning branded gifts for my team. The company has sporadic training opportunities, including required courses and optional courses. I try to find time for stuff, especially if it is relevant to my job. Making myself better on my company's dime is a win-win. Writing I write a lot more than I expected in my current job. Here are a few things that may require documentation: I might write an intake document to bring a new product brief to our team. This summarizes the information from our product owner, along with other tech details from other teams about how this initiative comes together. It will feed into the team's engineering research spike. I may be crafting a new team procedure, such as documenting on call responsibilities, updating onboarding docs, creating Service Level Objectives (SLOs) and Indicators (SLIs), or creating key results related to objectives (OKRs). I might be writing up my own product brief for a tech driven initiative. This allows me to sell it to my manager, and our product owners as a priority the team should take on. To Summarize: My day is meetings, researching, and writing. I miss coding, which is primarily done in my spare time as part of this blog or writing. What is a Typical Sprint? It is a lot easier to tell you what my typical sprint will look like than a typical day. A Sprint is a two-week development cycle, with a defined scope of work for the team and clear goals. Our sprints are done on a two-week cadence, so 10 working days. Day 1 I start with a pre-planning meeting with my team's project manager and my manager. This is to take a look at the goals for the sprint, and choose the related tickets. The full team also does retro from the last sprint. What went well, what didn't, and what can we do better? If you're a programmer you're probably used to this type of meeting. Then we do real sprint planning, where we communicate out the sprint goals for the team, talk about velocity, available points for each person, and choose tickets. Day 1 coincides with our on-call person rotation, so we do on-call transition meeting to talk about issues from the last week, and double check on the schedule for the upcoming week. Sometimes work may come out of this meeting, such as documenting things for our runbook. Day 2 This is a no meeting across my org, so I catch up on a lot of the research and writing I talk about above. Day 3 This is one of the days we do in person standup. An agile ceremony where the team shares their status. We also have a backlog refinement meeting, where the team will discuss and point tickets. We also perform a sync with our product owners to talk about the ongoing work and long term roadmap. The team is invited, but optional on this one. Day 4 This day contains a leadership meeting, which is just a status all ongoing work in our department. Day 5 This day is a different leadership meeting that is a check-in on the org. Leadership is asking the people managers and project manager's about quality of life, any issues that need to be raised, or any other ongoing problems. Day 6 My team, once again, does in person standup on day six. We also have a sync with our designer, to talk about ongoing work, or more likely to jump in on future work. There is another on call transition meeting, where we once again talk about issues of the last week and check the schedule for the previous week. I also have a leadership meeting, focused on upcoming work to our division, and the various teams involved. Day 7 This is the other no meeting day across our org, so once again I try to catch up on a lot of research and writing that I mentioned above. Day 8 This is a repeat of Day 3, with in person standup, a sync with our product owners, and ticket backlog refinement. Day 9 This is a leadership meeting all about my team, similar to the one on day 5, but instead of just the org it is focused on my team only. Day 10 This is a repeat of day 5. Then we go back to day 1, and repeat. On days, where the team does not meet in person we do Geekbot for standup, and I do read through all the updates. I like this form of async status updates, because it allows the devs to get focus time. One to One Meetings Now you know that my two-week cadence contains a lot of meetings, but as you probably guessed this isn't 8 hours of a day of meetings. Thankfully! On any given day I'll have at least a single 1:1 with someone, let's talk about them. My Dev Team: I might have a 1:1 with a team member who reports to me. I Try to keep these focused on professional development and less about the current work status. There are plenty of avenues to find out about the work status, including JIRA boards, application deployments, standups (or GeekBot statuses), or any given ad hoc meeting if a problem does persist. I also have 1:1 meetings with my project manager to discuss team stuff. We may be checking in the roadmap, or making a plan for our next product checkin, or chatting about how to organize the wiki, or about policies we may need to institute with the team. There is also a 1:1 with my boss. More often than not this is a status meeting about ongoing team work, while also touching on company topics such as return to office, vacation, or other corporate policies. We may brainstorm on various issues going on with the team. There is another 1:1 meeting with my product owner, to help plan for future projects, or clarify requirements around upcoming stuff. We do a lot of chatting async as needed, but it is nice to do so zoom to zoom when needed. Although, less frequent I'll have a 1:1 with my manager's manager, which is often about team status. Sometimes, I'll get together with our designer, which is often about ongoing projects. This is less consistent, but does happen. I'm also active in the company's mentoring program. At any given time I have a mentee or two, along with a mentor of my own. Depending on the person, and how long our relationship has been, I meet with them anywhere from every 2 weeks to every other month. I appreciate these relationships with people who expose me to completely different jobs, or other aspects of the company. Many to Many Meetings I already spoke about recurring team meetings in my typical sprint, and dove deep into the type of 1:1s I have. But, there are some other meetings, that didn't quite fit into either of those categories. The first is a manager status meeting with all of my manager's direct reports. This is primarily communication about company high level procedures, or a place to have open discussions about team feedback. If I'm involved in any DE&I working groups or other extra-curricular activities, there will usually be a meeting around that. The free time I collected around all these meetings is all about the research and writing I mentioned above. Typical Year I've been a manager for about a year and a half, and I'm starting to see some patterns. There are a bunch of meetings, or initiatives, that are routine, but not sprint focused. On a monthly basis, we have team demos, both for our sibling teams in the same department and for the wider company. It is a great way to tell what we're doing. I'm not usually the one giving these, but rather coordinating with the team so one of them can give the presentation. On a quarterly basis, we'll perform ICE reviews of our roadmap with our product owners. ICE stands for Impact, Confidence, and Ease, and is a way of evaluating all the planned or upcoming projects to determine business priority. Different Town Halls meetings happen routinely. This is where everyone gets together to listen to leadership talk about initiatives, outline a plan, and commend teams or developers who have been doing awesome. These can happen within my department, or within my org, or at any given leadership level of the company. There is usually at least one a month. For some of them, I may be presenting about my team, or submitting developers for spotlight callouts. This is part of my ad-hoc writing time around the other meetings. Sometimes we do midyear reviews, and we always do end of year reviews. As part of this, I Write up a manager review of every team member that reports to me. I may collect 360 feedback from other people they've worked with--on their team and external to the team. I combine all this info into a doc, that is hopefully informative, and actionable. Highlight their strengths and point out areas for improvement. These are hard to write, and it takes me up to two weeks. Out of year end reviews, will come a professional development plan. How can we make the team members better this year? What are they interested in learning about, or improving? These are primarily driven by the employee, but there do provide things to check up on throughout the year. I may have to prepare promotion docs for my team members to present to my leadership. This includes collecting feedback from others in the org, writing information about how they excelled and making a case for how they were working at the next level. Once again, this is usually a couple of weeks to put this all together, summarizing each expectation at the next level and proving my teammate meets the criteria for the next level. Near the end of the year there is something called a team calibration meeting. I evaluate each employee against the current expectations at their job role. I believe they use an approach called 4 box, so each employee, so on each expectation they get a 1-4. One means needs improvement; two means expectations; three means excelling; and four means doing freakin' amazing. The expectation is most people will land between 2 and 3 I hate to call this procedure stack ranking, because we are only evaluating employees against the expectations of their role. But, at the end each one has a number, which in essence compares them against each other. With the rise of distributed workforces and so much work from home, I'll routinely have "virtual water cooler" group meetings with others in the org. This is the time to hang out, chat about the weekend, latest shows, sports, and sometimes play games. Final Thoughts I still like being me, so in my spare time above all of this, I still keep myself busy with non-recurring extracurricular activities. It might be contributing to the company blog or preparing an internal presentation. I have been leading a team for about a year and a half, and sometimes I feel like I'm still figuring this out. I miss being knee deep in code and architecture every day, however, leading a team managerially has been a rewarding experience and it is nice to see the other side of the curtain.

From: Jeffry Houser's Blog

Happy New Year

Happy New Year Everyone! I started writing this after my first day at work in 2023, and have been tweaking it for the past week. 2022 was a rough year. My focus has been pulled in many directions, and I'm glad to be starting fresh. Here are some a lot of thoughts about the last year. Blog Stats Here are some stats from the blog: I wrote 57 posts last year, which is more than one a week. Despite this impressive number, my posts were very sporadic this year. Family health issues, including my own bout with COVID, forced me to juggle my schedule and I was not as consistent in my weekly posts. I overcompensated later in the year to make up for lost time. My most popular post was on Angular, about a bug when upgrading from Angular 12 to 13 I had 38,000 total views, which is not too shabby. I wrote a lot about Angular and TypeScript, comprising more than half the posts I wrote this year. No surprise, since I deal with that stuff a lot. I want to redesign the blog to something more modern and responsive, but I'm not going to promise to do that because other things keep taking precedence. After writing weekly posts for over 7 years, I'm going to make a big change, I'm going to focus on fewer, longer posts instead of a larger number of shorter posts. I hope it will allow me to drill deeper into specific topics. YouTube Stats I finally got vanity URLs for both my personal YouTube Channel and my DotComIt YouTube channel. For DotComIt, I had 23.4 thousand views and over 62,000 minutes. These are pretty cool numbers. Music I hooked my Alexa devices up to my Spotify account, and it plays a lot of random stuff. As such the bulk of bands in my instafest are ones I've never heard of. On my own musical journey, I wrote 16 new songs for February Album Writing Month, hiding away in my home studio. Some friends are encouraging me to start releasing stuff, but I'm not sure I want to take on yet another side project. What do you think? For the moment, I've turned my attention to digitizing my cassette collection. These are a lot of "one of a kind" tapes of bands I was in, or bands I recorded that I'd like to be able to listen to or send back to the band in question. It is a fun side project, and I just had to replace all the belts in the cassette deck to continue on. Books My Learn-With Series is going strong. I've updated it for both Angular 14 and Angular 15 this year. I expect to continue to update it as new versions come out. Most recently, I added a new chapter to the programming bonus books all about Angular's Standalone Components. My writing exists primarily so I can explore new ideas. My favorite part is adding new chapters about new approaches. The fact that I can make some extra cash on the other end is a bonus, although I struggle to keep the business profitable, since consulting is no longer my primary source of income. Thank you for all the continued support. Mailing List I'd love to say I continuously send monthly emails, but in 2022 I only sent 5 newsletters. That is not the consistent cadence I wish I was at. Since MailChimp increased their prices for a mailing list of my size, I am looking for alternate, cheaper, options. Family I mentioned family health issues earlier in this newsletter. Well, in early 2022, my mother-in-law moved in with us on home hospice care, eventually passing in late summer. That was a major life change that hit us overnight. I also got COVID for the first time. It knocked me out for a few days, and I had a lingering cough for 6 weeks or so. It eventually dissipated and I'm fine now. Career DotComIt has taken on very few consulting clients, since the bulk of my time goes to a day job now. As such, DotComIt is not currently profitable, as the book sales are not high enough to cover things like web hosting. I'll be having a conversation with my account and legal team to figure out the path forward. I don't want to stop writing blogs or publishing books. I stepped into a management position on my current project, which is a radically different skill than programming. I'm figuring it out and taking up all the training they can throw at me. Final Thoughts I'm honestly not sure what to expect from 2023, except a lot of recovery and a lot of house cleaning. My career and writing will continue as it always does, and I'll continue to adapt to new things. What are you planning for the 2023?

From: Jeffry Houser's Blog

@angular/Localize already installed, but ng bootstrap says it needs it

While updating Learn With Series for Angular 15 I can across an odd issue. I installed ng bootstrap and ran it in the browser, and got this issue: That is a pretty clear error, and how to solve it, I thought. Great. So I ran the command: ng add @angular/localize At my console, and was surprised at the response: NG Bootstrap thinks that it needs this new library to be added. Angular thinks it is already installed. What happened? When Angular 15 came out, they removed the polyfills file entirely. Polyfills are now added in the Angular.json file. I had to set up the localize polyfill manually. Open up Angular.json file in the root of your project, and search for polyfills. You should find them at project.myproject.architect.build.options, and it probably looks something like this: "polyfills": [ "zone.js" ], Just add your new polyfill: "polyfills": [ "zone.js", "@angular/localize/init" ], Restart your Angular CLI and you will be off to the races.

From: Jeffry Houser's Blog

Showing a Tooltip on a Div with Just CSS

In my previous post I blogged about truncating content in a DIV only using CSS. I wanted to revisit that and show you how to add a tooltip to that same truncated div using CSS. The theory is that if you truncate the text, you'll want the user to be able to see the full text. One way to do that is by adding a tooltip. I was surprised that divs don't intuitively support tooltips, but I did some searching and . found a cool way to do it.. I'm going to build off the example from my previous post, so we can assume we already have a div with content that is truncated. Now let's add two new CSS elements. One for tooltiptrigger, and one for tooltiptext. First, add this: .tooltiptrigger .tooltiptext { visibility: hidden; background-color: grey; color: white; position: absolute; z-index: 1; } Here, we're creating a CSS hierarchy where the tooltiptext must be inside the tooltiptrigger. The tooltiptext is hidden by default, has some background color in grey, and some foreground color in white. The z-index is set to 1 so that it shows up on top of other elements of the page . And finally, the position is absolute. Let's add another set of CSS: .tooltiptrigger:hover .tooltiptext { visibility: visible; } This means that whenever we hover over the tooltip trigger, the tooltiptext will become visible. Let's go back to the HTML This is something with a lot of text. The Quick Brown Fox Jumped over the Lazy Dogs. The whole purpose here is to extend the text beyond multiple lines with a lot of space so that we can demonstrate truncating it inside a div that has multiple lines and extra dots. This is something with a lot of text. The Quick Brown Fox Jumped over the Lazy Dogs. The whole purpose here is to extend the text beyond multiple lines with a lot of space so that we can demonstrate truncating it inside a div that has multiple lines and extra dots. The hierarchy of the HTML is that the tooltiptext is nested inside the tooltiptrigger div. The truncated text will show the tooltip when we roll over it. I do not like that we are replicating the full text in two sections here, but if we were building something in a single page framework, or generating the HTML from a service we could easily solve that. Run this code: And now rollover the text: Walah! It works. What I did not devote time to placement of the tooltip, but we could easily do so using CSS positioning elements. Play with it over on Plunker.

From: Jeffry Houser's Blog

Truncating multi-line text in a Div

I've been working on a project where we have a big description field that we want to display to our users. The field is of indeterminate length. If it expands beyond the scope of our allotted space in the UI, we want to automatically truncate that and show an ellipse. How do we make that work? Some CSS magic. First, let's create a div with a lot of text: This is something with a lot of text. The Quick Brown Fox Jumped over the Lazy Dogs. The whole purpose here is to extend the text beyond multiple lines with a lot of space so that we can demonstrate truncating it inside a div that has multiple lines and extra dots. Nothing special about that. Let's add some magic CSS to force the text to truncate: .truncatedDiv { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden } We're using a lot of weird properties. What is going on here? First, we set the display property to webkit-box. This is a special, experimental display version built for web kit. It is, however, supported in most browsers. The webkit-box text prepends the following properties. Next, we use webkit-box-orient which tells us which way the text flows. The webkit-line-clamp property tells CSS at what point we need to truncate the text. In this case, right after line 2. Finally, we add overflow: hidden to make sure the text after our second line is truncated. It should look a bit like this: I experimented a bit with looking for ways to do this without using the webkit-box, but did not see anything as easy or trivial. Play with the code here

From: Jeffry Houser's Blog

Using Volta to Switch between versions of NodeJS

I threw together this video about using Volta with multiple NodeJS projects. This video felt a bit haphazard, as it is still pretty new to me, but I learned a bit while recording it and that is good!

From: Jeffry Houser's Blog

Angular 15 is Out

Angular 15 is out. I've done an update to my main books and am working on the ones right now. Ivy is more mature now, and a lot of the external libraries worked fine without issue. With Angular 14 I had issues w/ external libs. I look forward to diving deep into stand alone components, and I'll be writing a chapter--and probably a few blog posts--about that early next year.

From: Jeffry Houser's Blog

How do you Deploy an Angular app?

This question comes in from a reader of one of my books, who was curious about how to deploy an Angular application to his ColdFusion server. The Learn with books primarily focus on the development process and I don't cover the dev ops or deployment side of things. My question: besides working locally while reading the book, I am assuming that I need to find a server that offers ColdFusion and allows me to work with Node, correct? This is what I told him. For local development, you can run both ColdFusion and NodeJS locally with no issue. The Angular CLI has a development server, and you can set up a proxy to call your local ColdFusion server. This is covered in the book. All the backend services to the books use the same approach, including PHP, Java, and NodeJS. If you want to deploy the app to a production server, you can create a production build with the Angular CLI and that will give you HTML/CSS/JS files you can push up to your existing web server. You do not need to install NodeJS on the server for this to work. Howeer, If you want to do automated deployments using Jenkins, docker, and/or microservices, things get a bit more complex. In that situation, my team uses an NGINX Docker Image as the base and we move the production version of the Angular code into the NGINX root directory, so even with our production build we do not have NodeJS running a web server. I've never delved deep into the process for running and deploying an application even though that is the approach most modern teams use. Often we set it up once and forget about it. I hope this helps someone.

From: Jeffry Houser's Blog

What version of Node should I use with Angular?

Today I learned someone put together a chart to tell which version of NodeJS works best with which version of Angular. Check it out Here! I've never put too much thought into it, because I've never experienced incompatibilities with my local install of NodeJS and the version of Angular I'm using. We do have some different projects that require different versions of Node, though, and have been using Volta to manage that. I hope to get some posts about that in the coming months.

From: Jeffry Houser's Blog

How does the includes() method work on a JavaScript Array of Objects??

Earlier this week I wrote about how the JavaScript includes() method works on a string. I followed it up on a post about how includes() works on an array. The short summary is that for strings we're looking for a partial match of the target string to exist in the source string. For an array, we are looking for an exact match between the target string and a single element within the source array. After writing the post about searching a string array, I wanted to explore a bit about object arrays. On paper, object arrays work exactly string arrays do, however the comparison can be a bit confusing to newcomers to JavaScript. Let's start with an array of objects: let myArrayWithObjects = [ { word: 'The'}, { word:'Quick'}, { word:'Brown'}, { word: 'Fox'}, { word: 'Jumped'}, { word: 'Over'}, { word: 'The'}, { word: 'Lazy'}, { word: 'Dogs'} ]; Each object contains a single property, `word`. Now we can use includes to search for for items in that array console.log(myArrayWithObjects.includes('The Quick Brown Fox Jumped Over The Lazy Dogs')); // returns false. This will output a false response, since no strings exist in the array; only objects. That is what we'd expect. Let's create a new object variable: let compareObject1 = { word: 'Fox'}; From our perspective, as a human reviewing code it looks like this object is equal to an object within the array. What happens if we perform the includes()? console.log(myArrayWithObjects.includes(compareObject1)); Try it, and you'll see that the response if also false How come? Because even though the two objects look similar they are two independent objects. JavaScript performs this compare by looking at the object's space in memory and these two objects that look similar occupy different places in memory. If we set our source string to a real value insdie the array and use that to compare, we should get a true result: console.log(myArrayWithObjects.includes(myArrayWithObjects[4])); This is because the the target value is pointed at the same object instance that resides inside the array. The comparison is true. Play with a Plunker here. Every once in a while I have a developer conversations and go on a weird tangent, writing a bunch of blog posts to drill into something that should be simple and intuitive. I think this is one of those times, but I'm always happy to explore and share those explorations.

From: Jeffry Houser's Blog

How does the includes() method work on JavaScript Arrays?

Earlier this week I wrote about how the JavaScript includes() method works on a string. It works a bit differently on an array, and I wanted to go into that. When processing it on a string, the includes() method performs a partial match. If the argument string exists in the source, true is returned. Otherwise false is returned. However, when using includes() on an array, an exact match is required. Not a match to the array, but a match between the object to search for and an item inside the array. You can use includes() on an array to search through an item in that array. Let's start with a variable that's an array: let myArray = ['The', 'Quick', 'Brown', 'Fox', 'Jumped', 'Over', 'The', 'Lazy', 'Dogs']; Now we can use includes to search for for items in that array console.log(myArray.includes('Fox')); // returns true This will output a true since the string Fox is an element in the array. We can try a full string comparison: console.log(myArray.includes('The Quick Brown Fox Jumped Over The Lazy Dogs')); This will return false, because even though each work in the string is part of the array, the full string is not a full element on the array. What happens if you search for something not in the original string? Techincally we did that above, but here is a check with a new word not in the original array. console.log(myArray.includes('Doggies')); The value will return false. Play with a Plunker here. I think I'm gonna be back next week to do some testing with an object full of arrays.

From: Jeffry Houser's Blog

How does the includes() method work on JavaScript Strings?

I have a discussion with another developer about a section of code that had the use of the includes method on a string, and there was some confusion about what it did, and I thought I'd write this full blog post. The includes() JS method can be used on both strings and arrays, both with slightly different functionality. This post will focus on using it on a string. When using includes on a string it will look for the text you provide inside of a different string. You can use includes on a string to search through text in the source. Let's start with a variable that's a string: let myString = "The Quick Brown Fox Jumped Over The Lazy Dogs" Now we can use includes to search for other text in that string: console.log(myString.includes('Fox')); // returns true This will output a true since the word Fox is included as part of the full string. We can also do a full string comparison: console.log(myString.includes('The Quick Brown Fox Jumped Over The Lazy Dogs')); // returns true I do one comparisons here, using a string literal. We can also compare based on a different variable: console.log(myString.includes(myString)); // returns true What happens if you search for something not in the original string? The value will return false: console.log(myString.includes('Doggies')); // returns false The use case for this determine if an Angular interceptor should act on the current URL or not, but there are plenty of other use cases for this. My next post will talk about how includes works when you use it against an array. Play with a Plunker here.

From: Jeffry Houser's Blog

More on Date Conversions

I was recently working on an app where the user was entering one date, but the date was turning into something else. I hate it when this happens, and even had similar issues in the early versions of my Learn With book series. Usually this is a conversion issue between date entry in the UI, storage in backend service, and sending that data back to the UI. It drove me nuts, and I finally found a solution. I decided to store all dates in UTC format, and pass them on to the users in the same. When the user enters a date in the UI, you can turn it into UTC Format using the JS toISOString() function: let originalDate = new Date(); let isoString = originalDate.toISOString() console.log(isoString); You should see something like this in your console: 2022-11-09T14:41:56.202Z Now send this to your backend, and save it in your database as a date. All good! When your REST Services send that date string back to the UI, you can re-convert it into a date object for display: let dateObject = new Date(isoString); console.log(dateObject); The output should be something like this: Wed Nov 09 2022 09:41:56 GMT-0500 (Eastern Standard Time) I found this to be a great way to handle dates between the front end and backend of an application. Play with a Plunker here

From: Jeffry Houser's Blog

How do I Publish my own Docker Image?

In the initial rendition of the LearnWith book series, I gave instructions on how to create a database and populate it with SQL, but left no instructions or details on how to set up or install a DB Server from scratch. That was beyond the scope of the book. About a year ago, I switched over from using a locally installed SQL Server to one powered by Docker. This would give my readers and myself a lot more flexibility, and one less thing to think about when reading my books to learn about Angular. In the process of creating the docker image for all to share, I took a ton of screenshots and a ton of notes but didn't have time to write it up until now. I'm using SQL Server as the basis however you should be able to morph these instructions for any type of Docker Image. Here are my instructions for how to create and publish a Docker Image. Create Your Docker Repo First, you'll want to create an account and docker repository on the Docker Website. Go here and you should see something like this: For the purposes of this article, I am not going to connect it to a Github or Bitbucket account, because auto build is out of the current scope of this article. Create the Docker Image You'll need to install Docker on your dev machine. From there, you can create your first container: docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=StrongPass#12" -e "MSSQL_PID=Express" -p 1433:1433 -d --name "learnwithdb" mcr.microsoft.com/mssql/server:2019-latest What does this command do? Let's dissect it: docker run: This command tells docker to start running something. e: The e argument is an environment variable, meaning you're passing some value into the Docker Image. In this case, I'm setting the default password and telling it to pre-accept the EULA. I'm also telling it which version of SQL Server to use--Express, the free version. p: The p argument is the port, it means the external port 1433, will redirect to the internal port 1433. d: This means the docker image runs in detached mode. It starts and returns you to your console, instead of showing you the console of the docker image. name: This argument is used to specify the name of our new docker image. I used learnwithdb, since I am creating a database to use with my learn with books. mcr.microsoft.com/mssql/server:2019-latest: The final piece of the command, isn't actually an argument; it is a reference to the docker image that we're making a copy of, in this case I'm copying the latest version of Microsoft's SQL Server 2019 docker image release. You should see something like this: No real response from the client, but once this was done, I was able to open up the server in SQL Server enterprise Manager, create the database, create the tables, populate it with some sample data. I'll refrain from going into details of this, since the focus on publishing a docker image. Turn your Container into an Image What we've created now is a container that is a copy of a default docker image provided by Microsoft. We need to turn that container into our own docker image. To do that we use the docker commit command: docker commit learnwithdb You should see something like this: I added a docker image ls at the end of the screenshot so we could see that the new image was indeed created. Grab the imageId and add a tag to it: docker tag 684de5ad80b4 learnwithdb You should see something like this: You may need to stop and delete the original running docker container before continuing. To stop it: docker stop learnwithdb And then delete it: docker rm learnwithdb When prepping for this, I neglected to grab screenshots of these two commands, sorry. Start your new Docker Image Now you can start up your new docker image: docker run -p 1433:1433 -d --name "learnwithdb" learnwithdb This run command is a lot simpler than our previous one. Let's see what is here: docker run: This command tells docker to start running something. p: The p argument is the port, it means the external port 1433, will redirect to the internal port 1433. d: This means the docker image runs in detached mode. It starts and returns you to your console, instead of showing you the console of the docker image. name: This argument is used to specify the name of our new docker image. I used learnwithdb, since I am creating a database to use with my learn with books. learnwithdb: The final piece of the command, isn't actually an argument; it is a reference to the docker image that we're making a copy of, in this case I'm creating a container based off the image we just created, learnwithdb. You should see something like this: I added a docker ps command, to show me all the running containers, and we see our new one running. Grab the container ID and add a tag: docker tag 684de5ad80b4 learnwith/learn-with:learnwithdb This tag will relate to how the image is found on the docker site, in this case it is found at https://hub.docker.com/repository/docker/learnwith/learn-with . I named it after my book series and then another one related to the DB. It should look something like this: I added an docker images at the end to listed all the images. You can see the original one we created, and the new tag. Make the Image Available Now, we can push image to repo with this command: docker push learnwith/learn-with:learnwithdb You'll see something like this: Now, jump over to hub.docker.com to see your repos: Now other people should be able to use or set up the image. Final Test I went ahead and used Docker Desktop to delete the images and containers I just created. Now try to run this: docker run -p 1433:1433 -d --name "learnwithdb" learnwith/learn-with:learnwithdb You should see something like this: Congratulations; you're done! You can find my custom image at https://hub.docker.com/repository/docker/learnwith/learn-with.

From: Jeffry Houser's Blog

Why would I use an underscore as an argument to an arrow function?

{ // do stuff } This is weird syntax; what does it mean? First, you can create an arrow function in a few different ways. This is how I might do it commonly: (arg1) => { // do stuff } I like using parenthesis to surround the arguments. But, they are not required. If you only have a single argument you can leave out the parenthesis: arg1 => { // do stuff } Then, for an arrow functions where you don't care about the arguments, you can use a single character variable, like what I wrote about earlier this week. Use the underscore ('_') like what we started with: _ => { // do stuff } This is intended as short hand for saying "I don't care what the argument is; I'm going to ignore it inside this function." My personal feeling is that the short hand does not communicate that, at least not universally. As such my preference is to use parenthesis with no variable input into the function: () => { // do stuff } The reason for the short hand is that it is one less character to type. But, I'd argue that the latter approach with parenthesis is more readable. I'm not in a position where I have to cut down on keystrokes that significantly. How about you?

From: Jeffry Houser's Blog