Skip to content

What's New in @this-dot@route-config v1.2

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Recently, we introduced our first open source library to have easier access to RouterModule config's data property. If you haven't read about it yet, I recommend reading my colleague’s introductory blog post.

Since the first release, we received great feedback from the community, and we've been working on improving the developer experience using it. In this article, I'd like to share with you the new features we've introduced, and how to use them.

RouteDataDirective (*tdRouteData)

One of the new features we've introduced is a directive for directly accessing the current route data property from within the component's template. This is a structural directive that binds the whole data property to the local variable we define. To use it, we need to add a *tdRouteData directive attribute to a tag that we want in order to use some route's defined properties.

<div *tdRouteData="let routeData">
  <h1>{{ routeData.pageTitle }}</h1>
</div>

In the routeData, we have access to the whole data property (along with all the properties from the data properties defined in parent routes).

Given the following router configuration, we will display the correct title depending on the subpage we're currently on.

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: Example1Component,
        children: [
          {
            path: 'first',
            component: FirstComponent,
            data: {
              title: ['First component'],
            },
          },
          {
            path: 'second',
            component: SecondComponent,
            data: {
              title: ['Second component'],
            },
          },
          {
            path: '**',
            pathMatch: 'full',
            redirectTo: 'first',
          },
        ],
      },
    ]),
  ],
})
export class Example1Module {}

If you need to use multiple route properties within one component's template, it is recommended to only use *tdRouteData on one root tag (or ng-container in case your template doesn't have one top-level element). This way we only create one subscription to route's data per template.

<ng-container *tdRouteData="let routeData">
  <h1>{{ routeData.pageTitle }}</h1>
  <ul *ngFor="let item of routeData.someRouteItems">
    <li>{{ item }}</li>
  </ul>
</ng-container>

RouteDataHasDirective (*tdRouteDataHas)

The second new feature we've introduced is a directive similar to *tdRouteTags directive we've already shown in the previous article. The big difference is more configuration options. The new *tdRouteDataHas directive allows the developer to configure the property that this directive is using to determine which template to show. We can configure this via the tdRouteDataHasPropName input (or just propName using shorthand syntax). Let's see it in action.

<p *tdRouteDataHas="'showParagraphTag'; propName: 'customRouteTagsProp';">
  Go to first
</p>

Given the following router configuration, we will display the paragraph only on the first route, and not on the second route.

RouterModule.forChild([
  {
    path: '',
    component: Example2Component,
    children: [
      {
        path: 'first',
        component: FirstComponent,
        data: {
          customRouteTagsProp: ['showParagraphTag'],
        },
      },
      {
        path: 'second',
        component: SecondComponent,
        data: {
          customRouteTagsProp: [],
        },
      },
      {
        path: '**',
        pathMatch: 'full',
        redirectTo: 'first',
      },
    ],
  },
]);

Summary

This concludes the new features we've added since the first release. I would like to thank all the people that provided us with suggestions for those features! We're constantly looking for ways to improve our libraries, and encourage you to let us know about any questions or feature requests via an issue on our repository.

If you want to play with the new features, please have a go at this Stackblitz example.

In case you have any questions, you can always tweet or DM me at @ktrz. I'm always happy to help!

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

Overview of the New Signal APIs in Angular cover image

Overview of the New Signal APIs in Angular

Overview of the New Signal APIs in Angular Google's Minko Gechev and Jeremy Elbourn announced many exciting things at NG Conf 2024. Among them is the addition of several new signal-based APIs. They are already in developer preview, so we can play around with them. Let's dig into it, starting with signal-based inputs and the new matching outputs API. Signal Based Inputs Discussions about signal-based inputs have been taking place in the Angular community for some time now, and they are finally here. Until now, you used the @Input() decorator to define inputs. This is what you'd have to write in your component to declare an optional and a required input: ` With the new signal-based inputs, you can write much less boilerplate code. Here is how you can define the same inputs using the new syntax: ` It's not only less boilerplate, but because the values are signals, you can also use them directly in computed signals and effects. That, effectively, means you get to avoid computing combined values in ngOnChanges or using setters for your inputs to be able to compute derived values. In addition, input signals are read-only. The New Output I intentionally avoid calling them signal-based outputs because they are not. They still work the same way as the old outputs. The Angular team has just introduced a new output API that is more consistent with the latest inputs API and allows you to write less boilerplate, similar to the new input API. Here is how you would define an output until now: ` Here is how you can define the same output using the new syntax: ` The thing I like about the new output API is that sometimes it happens to me that I forget to instantiate the EventEmitter because I do this instead: ` You won't forget to instantiate the output with the new syntax because the output function does it for you. Signal Queries I am sure most readers know the @ViewChild, @ViewChildren, @ContentChild, and @ContentChildren decorators very well and have experienced the pain of triggering the infamous ExpressionChangedAfterItHasBeenCheckedError or having the values unavailable when needed. Here is a refresher on how you would use these decorators until now: ` With the new signal queries, similar to the new input API, the values are signals, and you can use them directly in computed signals and effects. You can define the same queries using the new syntax: ` Jeremy Elbourn mentioned that the new signal queries have better type inference and are more consistent with the new input and output APIs. He also showcased a brand new feature not available with the old queries. You can now define a query as required, and the Angular compiler will throw an error if the query has no result, guaranteeing that the value won't be undefined. Here is how you can define a required query: ` Model Inputs Jeremy and Minko announced the last new feature is the model inputs. The name is vague, but the feature is cool—it simplifies the definition of two-way bindings. Until now, to achieve two-way binding, you would have to define an input and an output following a given naming convention. @Input and @Output had to be defined with the same name (followed by "Change" in the case of the output). Then, you could use the template's [()] syntax. ` ` That way, you could keep the value in sync between the parent and the child component. With the new model inputs, you can define a two-way binding with a single line of code. Here is how you can define the same two-way binding using the new syntax: ` The html template stays the same: ` The model function returns a writable signal that can be updated directly. The value will be propagated back to any two-way bindings. Conclusion The new signal-based APIs are a great addition to Angular. They allow you to write less boilerplate code and make your components more reactive. The new APIs are already in developer preview, so you can start playing around with them today. I look forward to seeing how the community will adopt these new features and what other exciting things the Angular team has in store for us, such as zoneless apps by default....

Using HttpClient in Modern Angular Applications cover image

Using HttpClient in Modern Angular Applications

Introduction With all the wonderful treats that the Angular team has given us during the recent "renaissance" era, many new developers are joining in on the fun. And one of the challenges they'll face at some point is how to call an API from your Angular application properly. Unfortunately, while searching for a guide on how to do this, they might stumble upon a lot of outdated information. Hence, this article should serve as a reliable guide on how to use the HttpClient in Angular >= 17. The Setup To make an HTTP request in Angular, you can take advantage of the HttpClient provided by the @angular/common/http package. To use it, you'll need to provide it. Here's how you can do that for the whole application using the bootstrapApplication function from @angular/platform-browser: ` With that, you should be good to go. You can now inject the HttpClient into any service or component in your application. Using HttpClient in Services Let's take a common example: You have a database object, say a Movie, and you want to implement CRUD operations on it. Typically, you'll want to create a service that provides methods for these operations. Let's call this service MovieService and create a skeleton for it with a method for getting all movies. ` Implementing the Method using HttpClient Let's assume we have a GraphQL API for our movies. We can implement our getAllMovies using HttpClient to make a request to fetch all movies. First, we will need to define a new type to represent the response from the API. This is especially important when you are using GraphQL, which may return a specific structure, such as: ` When working with a real API, you'll likely use some code generator to generate the types for the response from the GraphQL schema. But for the sake of this example, we'll create an interface to represent the response manually: ` Now, we can implement the getAllMovies method using HttpClient: ` > Note: The post method is used here because we are sending a request body. If you are making a GET request (e.g. to a REST API), you can use the get method instead. The getAllMovies method returns an Observable of MoviesListResponse. In this example, I have typed it explicitly to make it obvious at first glance, but you could also omit the type annotation, and TypeScript should infer it. > Note: While I'm excited about signals as much as the next guy, making HTTP requests is one of the typical async operations for which RxJS Observables are a perfect fit, making a great argument for RxJS still having a solid place in Angular alongside signals. Using the Service in a Component Now that we have our MovieService set up, we can use it as a component to fetch and display all movies. But first, let's create a Movie interface to represent the structure of a movie. Trust me, this will prevent many potential headaches down the line. Although using any at the beginning and implementing the types later is a valid approach in some cases, using data fetched from an API without validating the type will inevitably lead to bugs that are difficult to solve. ` Now, we can start implementing our standalone MoviesComponent: ` In this component, we are calling the getAllMovies method from the MovieService in the constructor to fetch all movies and assign them to the movies property which we will use to display the movies in the template. ` In this case, placing our code inside the constructor is safe because it doesn’t depend on any @Input(). If it were, our code would fail because the inputs aren’t initialized at time of instantiation. That's why it is sometimes recommended to place logic in ngOnInit instead. You could also put this call in an arbitrary method that is called e.g. on a button click. Another way to handle the subscription is to use the async pipe in the template. This way, Angular will automatically subscribe and unsubscribe from the observable for you and you won't have to assign the response to a property in the component. Due to the structure of the returned data, however, we'll need to use the RxJS map operator to extract the movies from the response. ` > Note using the pipe method to chain the map operator to the observable returned by getAllMovies. This is a common pattern when working with RxJS observables introduced in RxJs 5.5. If you see code that uses the map operator directly on the observable and wonder why it isn't working for you, it's likely using an older version of RxJS. Now, we can simply apply the async pipe in the template to subscribe to the observable and display the movies: ` Conclusion HttpClient in Angular is pretty straightforward, but with all the changes to RxJS and Angular in the past few years, it can pose a significant challenge if you're not super-experienced with those technologies and stumble upon outdated resources. Following this article, you should hopefully be able to implement your service using HttpClient to make requests to an API in your modern Angular application and avoid the struggle of copying outdated code snippets....

Getting Started with Custom Structural Directives in Angular cover image

Getting Started with Custom Structural Directives in Angular

Introduction Angular comes with many built-in directives. Some of them (eg. NgIf, NgModel or FormControlDirective) are used daily by Angular developers. Those directives can be split into 2 categories: - Attribute directives They can be used to modify the appearance of behavior of Angular components and DOM elements. For example: - RouterLink - NgModel - FormControlDirective - Structural directives They can be used to manipulate the HTML structure in the DOM. Using them, we can change the structure of part of the DOM that they control. For example: - NgIf - NgForOf - NgSwitch In this article, I will focus on the latter. Creating a custom structural directive As I've mentioned above, there are a couple of built-in structural directives in Angular. However, we might come across a case that the ones provided with the framework don't solve. This is where a custom structural directive might help us resolve the issue. But how do we write one? --- All the code examples in this article use the Angular CLI or Nx CLI generated project as a starting point. You can generate a project using the following command, or use Stackblitz starter project. ` --- NgIf directive clone Let's learn the basic concepts by reimplementing the basic features of the NgIf directive. We will call it CsdIf (CSR prefix stands for Custom Structural Directive :)) The structural directive is actually just a regular directive (with some additional syntactic sugars provided by Angular). So we can start with creating a module and empty directive using AngularCLI: ` our new directive should look like this: ` Let's implement the basic functionality of displaying the content if passed value is true. ` To achieve that, we need a couple of elements: - an input that will determine whether to show or hide the content (@Input) - a reference to the template that we want to conditionally display (TemplateRef) - a container that will provide us with access to Angular's view (ViewContainerRef) The input can be just a regular class property with Angular's @Input decorator. The important thing is to use a proper naming convention. For it to work as it does in the example code shown above, we need to name the property the same as the attribute's selector: ` Now our directive has the information whether to display the content or not but we need to also gain access to the TemplateRef and ViewContainerRef instances. We can do that by injecting them via a constructor: ` Now we have all the necessary tools and information to display or hide the content. We can use ViewContainerRef's createEmbeddedView method to display and clear method to remove the content. Important note: To make sure the csdIf property is assigned already, we need to use ngOnInit lifecycle hook. ` With this implementation, the following example already works as expected. ` There is still a problem with this implementation. Let's try to use the following example: ` The "My conditional header" is displayed correctly when the page renders but as soon as we uncheck the showInput, our header doesn't disappear as we would expect. This is because we only check the csdIf input value inside of ngOnInit, but we do not react to the input's changes. To resolve this, we can either use ngOnChanges lifecycle hook or modify the csdIf to be a setter rather than just a property. I will show you the later solution but implementing it using ngOnChanges should be very similar. As a first step, let's modify the csdIf to be a setter, and store its value in a private property show. ` Secondly, when the new csdIf value is set, we need to perform the same logic as we do in ngOnInit. We need to make sure though that we don't render the template twice so we can clear the view first in all cases. ` As a final step, let's refactor to remove the code duplication by extracting the common logic into a method. ` Now, our second example works as expected: ` Handling additional parameters - else template The CsdIf directive shows and hides the content based on the boolean input correctly. But the original NgIf directive allows for specifying an alternative template via the "else" property as well. How do we achieve this behavior in our custom directive? This is where understanding the "syntactic sugar" that stands behind the structural directives is crucial. The following NgIf syntax: ` is actually equivalent to the following syntax: ` This means that the else property is actually becoming ngIfElse input parameter. In general, we can construct the property name by concatenating the attribute following * and the capitalized property name (eg. "ngIf" + "Else" = "ngIfElse""). In case of our custom directive it will become "csdIf" + "Else" = "csdIfElse ` is equivalent to ` By analyzing the "unwrapped" syntax we can notice the the reference to an alternative template is passed via the csdIfElse property. Let's add and handle that property in the custom directive implementation: ` This addition makes our directive much more useful, and allows for displaying content for cases when the condition is true or false. If something is not clear, or you want to play with the example directive please visit the example on Stackblitz. Real life example The above example is very simple, but it gives you tools to create your own custom directive when you need it. If you want to have a look at some real-life custom directive example that we've found useful at This Dot Labs, I suggest checking out our route-config open source library. You can read more about it in one of our articles: - Introducing @this-dot/route-config - What's new in @this-dot@route-config v1.2 Summary In this article, we've learnt how to write a simple custom structural directive that handles additional inputs. We've covered the syntactic sugar that stands behind the structural directive, and how it translates into directive's inputs. In the second part, I will show you how to add some additional functionalities to the custom structural directive and present ways to improve type checking experience for the custom directive's templates. In case you have any questions, you can always tweet or DM me at @ktrz. I'm always happy to help!...

The simplicity of deploying an MCP server on Vercel cover image

The simplicity of deploying an MCP server on Vercel

The current Model Context Protocol (MCP) spec is shifting developers toward lightweight, stateless servers that serve as tool providers for LLM agents. These MCP servers communicate over HTTP, with OAuth handled clientside. Vercel’s infrastructure makes it easy to iterate quickly and ship agentic AI tools without overhead. Example of Lightweight MCP Server Design At This Dot Labs, we built an MCP server that leverages the DocuSign Navigator API. The tools, like `get_agreements`, make a request to the DocuSign API to fetch data and then respond in an LLM-friendly way. ` Before the MCP can request anything, it needs to guide the client on how to kick off OAuth. This involves providing some MCP spec metadata API endpoints that include necessary information about where to obtain authorization tokens and what resources it can access. By understanding these details, the client can seamlessly initiate the OAuth process, ensuring secure and efficient data access. The Oauth flow begins when the user's LLM client makes a request without a valid auth token. In this case they’ll get a 401 response from our server with a WWW-Authenticate header, and then the client will leverage the metadata we exposed to discover the authorization server. Next, the OAuth flow kicks off directly with Docusign as directed by the metadata. Once the client has the token, it passes it in the Authorization header for tool requests to the API. ` This minimal set of API routes enables me to fetch Docusign Navigator data using natural language in my agent chat interface. Deployment Options I deployed this MCP server two different ways: as a Fastify backend and then by Vercel functions. Seeing how simple my Fastify MCP server was, and not really having a plan for deployment yet, I was eager to rewrite it for Vercel. The case for Vercel: * My own familiarity with Next.js API deployment * Fit for architecture * The extremely simple deployment process * Deploy previews (the eternal Vercel customer conversion feature, IMO) Previews of unfamiliar territory Did you know that the MCP spec doesn’t “just work” for use as ChatGPT tooling? Neither did I, and I had to experiment to prove out requirements that I was unfamiliar with. Part of moving fast for me was just deploying Vercel previews right out of the CLI so I could test my API as a Connector in ChatGPT. This was a great workflow for me, and invaluable for the team in code review. Stuff I’m Not Worried About Vercel’s mcp-handler package made setup effortless by abstracting away some of the complexity of implementing the MCP server. It gives you a drop-in way to define tools, setup https-streaming, and handle Oauth. By building on Vercel’s ecosystem, I can focus entirely on shipping my product without worrying about deployment, scaling, or server management. Everything just works. ` A Brief Case for MCP on Next.js Building an API without Next.js on Vercel is straightforward. Though, I’d be happy deploying this as a Next.js app, with the frontend features serving as the documentation, or the tools being a part of your website's agentic capabilities. Overall, this lowers the barrier to building any MCP you want for yourself, and I think that’s cool. Conclusion I'll avoid quoting Vercel documentation in this post. AI tooling is a critical component of this natural language UI, and we just want to ship. I declare Vercel is excellent for stateless MCP servers served over http....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co