Page Contents

Define the model relation

We are going to add the model relation to indicate the relation that TodoList hasMany Todo using the lb4 relation command.

$ lb4 relation
? Please select the relation type hasMany
? Please select source model TodoList
? Please select target model Todo
? Foreign key name to define on the target model todoListId
? Source property name for the relation getter (will be the relation name) todos
? Allow TodoList queries to include data from related Todo instances? Yes
   create src/controllers/todo-list-todo.controller.ts

Relation HasMany was created in src/

Now, we’re going to add the relation for Todo. That is, Todo belongsTo TodoList.

$ lb4 relation
? Please select the relation type belongsTo
? Please select source model Todo
? Please select target model TodoList
? Foreign key name to define on the source model todoListId
? Relation name todoList
? Allow Todo queries to include data from related TodoList instances? Yes
   create src/controllers/todo-todo-list.controller.ts

Relation BelongsTo was created in src/

Update Sample Data

Now that we have the relations between the Todo and TodoList models, we can update the data we have in data/db.json to reflect this relation.

First let’s add two sample TodoLists:

{
  "ids": {
    "Todo": 5,
    "TodoList": 3
  },
  "models": {
    "Todo": {
      "1": "{\"title\":\"Take over the galaxy\",\"desc\":\"MWAHAHAHAHAHAHAHAHAHAHAHAHAMWAHAHAHAHAHAHAHAHAHAHAHAHA\",\"id\":1}",
      "2": "{\"title\":\"destroy alderaan\",\"desc\":\"Make sure there are no survivors left!\",\"id\":2}",
      "3": "{\"title\":\"play space invaders\",\"desc\":\"Become the very best!\",\"id\":3}",
      "4": "{\"title\":\"crush rebel scum\",\"desc\":\"Every.Last.One.\",\"id\":4}"
    },
    "TodoList": {
      "1": "{\"title\":\"Sith lord's check list\",\"color\":\"blue\",\"id\":1}",
      "2": "{\"title\":\"My daily chores\",\"color\":\"red\",\"id\":2}"
    }
  }
}

Next, let’s add a todoListId property to the Todos with the ids of the new TodoLists we added:

{
  "ids": {
    "Todo": 5,
    "TodoList": 3
  },
  "models": {
    "Todo": {
      "1": "{\"title\":\"Take over the galaxy\",\"desc\":\"MWAHAHAHAHAHAHAHAHAHAHAHAHAMWAHAHAHAHAHAHAHAHAHAHAHAHA\",\"todoListId\":1,\"id\":1}",
      "2": "{\"title\":\"destroy alderaan\",\"desc\":\"Make sure there are no survivors left!\",\"todoListId\":1,\"id\":2}",
      "3": "{\"title\":\"play space invaders\",\"desc\":\"Become the very best!\",\"todoListId\":2,\"id\":3}",
      "4": "{\"title\":\"crush rebel scum\",\"desc\":\"Every.Last.One.\",\"todoListId\":1,\"id\":4}"
    },
    "TodoList": {
      "1": "{\"title\":\"Sith lord's check list\",\"color\":\"blue\",\"id\":1}",
      "2": "{\"title\":\"My daily chores\",\"color\":\"red\",\"id\":2}"
    }
  }
}

Behind the scenes

If you want to understand the code changes introduced from the relation generator command, read on the details in this section; otherwise, you are ready to move to the next step to create the controller.

Relation decorators

When we added the hasMany relation using the lb4 relation command, it added the @hasMany() decorator together with the todos property. As the decorator’s name suggests, @hasMany() informs LoopBack 4 that a todo list can have many todo items.

export class TodoList extends Entity {
  // ...properties defined by the CLI...

  @hasMany(() => Todo)
  todos: Todo[];

  // ...constructor def...
}

Similarly for the belongsTo relation:

export class Todo extends Entity {
  // ...properties of the Todo model

  @belongsTo(() => TodoList)
  todoListId: number;

  // ...constructor def...
}

You’ll notice there’s a TodoRelations interface in the Todo model class file as well as a TodoWithRelations type defined.

src/models/todo.model.ts

export interface TodoRelations {
  // describe navigational properties here
}

export type TodoWithRelations = Todo & TodoRelations;

In the TodoRelations interface, we want to describe a todoList as a navigational property. We can do that as follows:

src/models/todo.model.ts

// add TodoListWithRelations to the following import
import {TodoList, TodoListWithRelations} from './todo-list.model';
export interface TodoRelations {
  // add the following line
  todoList?: TodoListWithRelations;
}

Let’s add a todo navigational property to the TodoList model as well:

src/models/todo-list.model.ts

// add TodoWithRelations to the following import
import {Todo, TodoWithRelations} from './todo.model';
export interface TodoListRelations {
  // add the following line
  todos?: TodoWithRelations[];
}

Further, when we ran the lb4 relation command, we accepted the default of Yes to the prompt:

? Allow Todo queries to include data from related TodoList instances? (Y/n)

This registers the inclusionResolver for the relation(s) you were working with above.

Make sure to choose ‘yes’ if you’d like to use inclusion and your model is traversable. In the example of getting the related Todo objects for each TodoList, it registers the inclusion resolver that comes with the HasManyRepositoryFactory.

Let’s take a closer look at the TodoListRepository.

src/repositories/todo-list.repository.ts

this.todos = this.createHasManyRepositoryFactoryFor(
  'todos',
  todoRepositoryGetter,
);
// this line enables inclusion for this relation
this.registerInclusionResolver('todos', this.todos.inclusionResolver);

As a result, when you get a TodoList, a todos property will be included that contains your related Todos, for example:

{
  "id": 2,
  "title": "My daily chores",
  "todos": [
    {
      "id": 3,
      "title": "play space invaders",
      "desc": "Become the very best!",
      "todoListId": 2
    }
  ]
}

On the other end, BelongsToAccessor also comes with an inclusion resolver function that we can register on the TodoRepository.

src/repositories/todo.repository.ts

this.todoList = this.createBelongsToAccessorFor(
  'todoList',
  todoListRepositoryGetter,
);
// this line enables inclusion for this relation
this.registerInclusionResolver('todoList', this.todoList.inclusionResolver);

There’s an additional relation type LoopBack 4 supports, which is hasOne. If you’re interested in trying it out, see Add TodoListImage Relation. This is not required for the application, so if you’d like to skip it, see the navigation for the last step.

Previous step: Add TodoList Repository

Last step: Add TodoList Controller