React render props in Angular world

Wojciech Trawiński
JavaScript everyday
3 min readNov 12, 2018

Some day my colleague asked me how to reuse smart components in Angular so that it would be possible to share application logic for different dumb/presentional components. I used to work with React for some time (shame on me!), therefore the obvious solution was to use render props. In this article I’m going to show you how it’s possible to achieve this feature with Angular.

Since the solution is based on content projection I highly recommend reading the following article by Eudes Petonnet or watching his talk at ng-conf 2018

Introduction

Suppose you are working on an application rendering math exercises. One of the application pages will be the exercise screen implemented using master-detail pattern. As a result you will need to provide an exercise navigation with buttons varying based on the application mode (let’s say that in homework mode a user should be focused on solving exercises and fancy buttons would definitely distract her/his attention).

Therefore, the goal is to implement the exercise-navigation component in such a way that a developer can freely change a dumb/presentional component responsible for rendering exercise item.

Implementation

In the following example I will render the exercise-navigation component with two button types, namely ordinary and fancy. Since I’m not good at CSS I will make a button fancy by simply making it round :).

The example can be found here:

Let’s investigate the crucial parts of the application

Models

Since a navigation button is expected to receive an input of a given form (item data and onclick handler), it is necessary to have a sort of contract.

Dumb/Presentional Components

For the sake of simplicity, a button component only differs in terms of CSS styles. However, in a real-world application they may differ much more, since the only constraint is to implement NavigationBtn interface. As you can see,the exerciseItem property is used to provide information on an item’s name, whereas the onItemSelected is a callback to be fired when the button has been clicked.

Smart Components

The choice on which dumb component to use as a navigation button is made within a component that renders exercise-navigation component. In the example it’s simply the root component.

The solution is to use content projection within app-exercise-navigation component. However, you don’t project a button component directly, since you wrap it with ng-template tag. Input properties for both ordinary and fancy button components will be passed on the basis of ng-template context (let-exerciseItem and let-onItemSelected are computed based on the provided context) which will be determined when the template is rendered (within app-exercise-navigation component).

Within the navigation component the projected TempateRef is grabbed with the aid of ContentChild decorator and is further used as a blueprint for rendering a navigation button.

*ngTemplateOutlet directive allows you to render a content based on the provided template, namely the navigation button template projected into app-exercise-navigation component. The input data for the button component is provided with the aid of context computed for each exerciseItem.

Conclusions

If you want to make use of render props in Angular you need to get familiar with TemplateRefs. In the article I presented the solution in which the blueprint is provided with the aid of content projection technique. In addition, an instance of TemplateRef can also be passed as an input property and used in the same way as content-projected template.

The presented solution is the best choice when you have a reusable logic encapsulated within a component and you want to provide some flexibility on how the content is presented. A perfect example would be a calender component with the ability to provide a component definition for rendering a day/week/month cell.

Like, love, hate, clap!

--

--