In this part of the tutorial I’m going to be making a mock service to house all my animal details. In the previous part of the mock data series I made a second set of classes for animals and identified the need to move them out to a single location.
Making Magic
Here is where the magic happens with this process. When I’ve identified duplicated data and move it to a central location not only does my code become more consistent and simplified but it is also more maintainable.
It is true that I am often working in prototype code so it really doesn’t “matter” that I have some duplication going on. Or even that the code isn’t maintainable because it’s all a prototype right now anyway.
I’m always pushing to make my code easier to fold into the process. I don’t want to spend time/effort/energy on writing the code just so someone else has to come back and rewrite it because I’m leaving it in a weird hard coded prototype state.
Don’t get me wrong. I totally started there where everything was hard coded and sometimes at first pass I leave things hard coded until I know what I want to do with the experience. Then I go back through and clean it up so that the interaction design can be tested and fully experienced in the coded prototype.
Creating my service
First thing I need to do is get my service created.
ng g s animal
Now that I have that created I am going to strip out my classes and interfaces from the other components and move them into the service. As I do this I combine them to make a single class eliminating the duplication.
This is going to make more sense when you look at the full code file on github but now I’ve got one file that combines all the data from both spots.
Here is a peek below.
export interface IAnimal {
guid: string;
name: string;
type: string;
description: string;
numberAtZoo: number;
photo: string;
animalInResidence: IAnimalInResidence[];
food: IFood[];
habitats: IHabitat[];
}
export interface IAnimalInResidence {
name: string;
personality: string;
age: number;
}
export interface IFood {
foodName: string;
}
export interface IHabitat {
habitatName: string;
}
Newing up my animal instances
First, I’m going to export a new abstract class in my AnimalService file. I want to be able to create this base class that will be extended by the mock service and not be instantiated which is where the abstract class is particularly useful.
Within this abstract class I call the getAll method to return all my animals from my mock data set.
I then called the abstract method get which takes an id and then returns an observable of type IAnimal.
export abstract class AnimalService {
abstract getAll(): Observable<IAnimal[]>;
abstract get(id: string): Observable<IAnimal>;
}
Extending my abstract class
Now that I’ve got my abstract class in place I want to extend the service to handle my mock data so I export a second class called the MockAnimalService and extend the Animal Service.
export class MockAnimalService extends AnimalService { … }
In this class I call the getAll method and return my 3 new animals.
export class MockAnimalService extends AnimalService {
getAll(): Observable<IAnimal[]> {
return of([
new Animal1(),
new Animal2(),
new Animal3()
]);
}
}
Next, I call the get method and pass in my guid. When I return the data from the get all method I then use the pipe() function to combine multiple functions. I then call map and get all the animals. I then use find to locate the animal with that guid.
get(guid: string): Observable<IAnimal> {
return this.getAll()
.pipe(
map(x => x.find(a => a.guid === guid))
);
}
This has now made the guid accessible for me to use in the URL and link to the correct animal.
Routing to the animal
This part is pretty straight forward but I want to include it anyway just in case it is helpful.
In my routing.module I add the following to the routes variable
{path: 'animals/:guid', component: AnimalComponent}
And within the animal list view I added the [routerLink] to grab that guid and build the route for me.
<a [routerLink]="['/animals', animal.guid]">{{animal.name}} </a>
Inside the animal.component.ts
Now it comes to the fun part. Building out my animal detail view by binding all the animal detail attributes in my mock data to the view.
<main class="animal-wrapper">
<h1>{{animal.name}}</h1>
<h3>{{animal.type}}</h3>
<p>{{animal.description}}</p>
<h5 *ngFor="let foodItem of animal.food">{{foodItem.name}}</h5>
<h5 *ngFor="let habitat of animal.habitats">{{location.name}}</h5>
...
</main>
Once I've got the attributes and properties from my mock service in place I'm ready to test my prototype.
To Wrap Up
In this series I walked through how I take my designs from clickable prototypes into full code prototypes. This has helped my clients and projects immerse themselves in the final experience quicker. We are able to get this into someones hands much quicker than full development and test out some of the more difficult to prototype experiences.
Top comments (0)