Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 23 additions & 28 deletions src/markdown/tutorial/part-1/07-reusable-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,22 @@ While adding the map, you will learn about:

## Managing Application-level Configurations

We will use the [Mapbox](https://www.mapbox.com) API to generate maps for our rental properties. You can [sign up](https://www.mapbox.com/signup/) for free and without a credit card.
We will use the [TomTom](https://developer.tomtom.com/map-display-api/documentation/product-information/introduction) API to generate maps for our rental properties. You can [sign up](https://developer.tomtom.com) for free and without a credit card.

Mapbox provides a [static map images API](https://docs.mapbox.com/api/maps/#static-images), which serves map images in PNG format. This means that we can generate the appropriate URL for the parameters we want and render the map using a standard `<img>` tag. Pretty neat!
TomTom provides a [static map images API](https://developer.tomtom.com/map-display-api/documentation/raster/static-image), which serves map images in PNG format. This means that we can generate the appropriate URL for the parameters we want and render the map using a standard `<img>` tag. Pretty neat!

If you're curious, you can explore the options available on Mapbox by using the [interactive playground](https://docs.mapbox.com/help/interactive-tools/static-api-playground/).

Once you have signed up for the service, grab your *[default public token](https://account.mapbox.com/access-tokens/)* and paste it into `config/environment.js`:
Once you have signed up, grab your *[default public token](https://developer.tomtom.com/user/me/apps)* and paste it into `config/environment.js`:

```run:file:patch lang=js cwd=super-rentals filename=config/environment.js
@@ -50,2 +50,4 @@

+ ENV.MAPBOX_ACCESS_TOKEN = 'paste your Mapbox access token here';
+ ENV.TOMTOM_ACCESS_TOKEN = 'paste your TomTom API key here';
+
return ENV;
```

As its name implies, `config/environment.js` is used to *configure* our app and store API keys like these. These values can be accessed from other parts of our app, and they can have different values depending on the current environment (which might be development, test, or production).

> Zoey says...
>
> If you prefer, you can [create different Mapbox access tokens](https://account.mapbox.com/access-tokens/) for use in different environments. At a minimum, the tokens will each need to have the "styles:tiles" scope in order to use Mapbox's static images API.

```run:command hidden=true cwd=super-rentals
pnpm ember test
git add config/environment.js
Expand All @@ -46,8 +40,8 @@ git add config/environment.js
```run:file:patch hidden=true cwd=super-rentals filename=config/environment.js
@@ -50,3 +50,3 @@

- ENV.MAPBOX_ACCESS_TOKEN = 'paste your Mapbox access token here';
+ ENV.MAPBOX_ACCESS_TOKEN = process.env.MAPBOX_ACCESS_TOKEN;
- ENV.TOMTOM_ACCESS_TOKEN = 'paste your TomTom API key here';
+ ENV.TOMTOM_ACCESS_TOKEN = process.env.TOMTOM_ACCESS_TOKEN;

```

Expand Down Expand Up @@ -77,7 +71,7 @@ npm start

## Generating a Component with a Component Class

With the Mapbox API key in place, let's generate a new component for our map.
With the TomTom API key in place, let's generate a new component for our map.

```run:command cwd=super-rentals
ember generate component map --component-class=@glimmer/component
Expand Down Expand Up @@ -108,7 +102,7 @@ Let's update our component:

export default class Map extends Component {
+ get token() {
+ return encodeURIComponent(ENV.MAPBOX_ACCESS_TOKEN);
+ return encodeURIComponent(ENV.TOMTOM_ACCESS_TOKEN);
+ }
+
<template>
Expand All @@ -128,7 +122,7 @@ Here, we import the access token from the config file and return it from a `toke

First, we have a container element for styling purposes.

Then we have an `<img>` tag to request and render the static map image from Mapbox.
Then we have an `<img>` tag to request and render the static map image from TomTom.

Our component's template contains several values that don't yet exist&mdash;`@lat`, `@lng`, `@zoom`, `@width`, and `@height`. These are *[arguments](../../../components/component-arguments-and-html-attributes/#toc_arguments)* to the `<Map>` component that we will supply when invoking it.

Expand All @@ -144,7 +138,7 @@ Next, we used `...attributes` to allow the invoker to further customize the `<im

Since the passed-in `alt` attribute (if any exists) will appear *after* ours, it will override the value we specified. On the other hand, it is important that we assign `src`, `width`, and `height` after `...attributes`, so that they don't get accidentally overwritten by the invoker.

The `src` attribute interpolates all the required parameters into the URL format for Mapbox's [static map image API](https://docs.mapbox.com/api/maps/#static-images), including the URL-escaped access token from `this.token`.
The `src` attribute interpolates all the required parameters into the URL format for TomTom's [static map image API](https://developer.tomtom.com/map-display-api/documentation/raster/static-image), including the URL-escaped access token from `this.token`.

Finally, since we are using the `@2x` "retina" image, we should specify the `width` and `height` attributes. Otherwise, the `<img>` will be rendered at twice the size than what we expected!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @2x query param is is specific to Mapbox, so this paragraph should be removed.


Expand Down Expand Up @@ -184,11 +178,11 @@ We just added a lot of behavior into a single component, so let's write some tes
+ .hasAttribute('height', '120');
+
+ let { src } = find('.map img');
+ let token = encodeURIComponent(ENV.MAPBOX_ACCESS_TOKEN);
+ let token = encodeURIComponent(ENV.TOMTOM_ACCESS_TOKEN);
+
+ assert.ok(
+ src.startsWith('https://api.mapbox.com/'),
+ 'the src starts with "https://api.mapbox.com/"',
+ src.startsWith('https://api.tomtom.com/'),
+ 'the src starts with "https://api.tomtom.com/"',
+ );
+
+ assert.ok(
Expand Down Expand Up @@ -245,13 +239,13 @@ We just added a lot of behavior into a single component, so let's write some tes
- assert.dom().hasText('template block text');
+ assert
+ .dom('.map img')
+ .hasAttribute('src', /^https:\/\/api\.mapbox\.com\//)
+ .hasAttribute('src', /^https:\/\/api\.tomtom\.com\//)
+ .hasAttribute('width', '150')
+ .hasAttribute('height', '120');
});
```

Note that the `hasAttribute` test helper from [`qunit-dom`](https://github.com/simplabs/qunit-dom/blob/master/API.md) supports using *[regular expressions](https://javascript.info/regexp-introduction)*. We used this feature to confirm that the `src` attribute starts with `https://api.mapbox.com/`, as opposed to requiring it to be an exact match against a string. This allows us to be reasonably confident that the code is working correctly, without being overly-detailed in our tests.
Note that the `hasAttribute` test helper from [`qunit-dom`](https://github.com/simplabs/qunit-dom/blob/master/API.md) supports using *[regular expressions](https://javascript.info/regexp-introduction)*. We used this feature to confirm that the `src` attribute starts with `https://api.tomtom.com/`, as opposed to requiring it to be an exact match against a string. This allows us to be reasonably confident that the code is working correctly, without being overly-detailed in our tests.

*Fingers crossed...* Let's run our tests.

Expand Down Expand Up @@ -297,7 +291,7 @@ wait .rentals li:nth-of-type(3) article.rental .map

> Zoey says...
>
> If the map image failed to load, make sure you have the correct `MAPBOX_ACCESS_TOKEN` set in `config/environment.js`. Don't forget to restart the development and test servers after editing your config file!
> If the map image failed to load, make sure you have the correct `TOMTOM_ACCESS_TOKEN` set in `config/environment.js`. Don't forget to restart the development and test servers after editing your config file!

For good measure, we will also add an assertion to the `<Rental>` tests to make sure we rendered the `<Map>` component successfully.

Expand Down Expand Up @@ -327,23 +321,23 @@ From within our JavaScript class, we have access to our component's arguments us
```run:file:patch lang=js cwd=super-rentals filename=app/components/map.gjs
@@ -3,3 +3,15 @@ import ENV from 'super-rentals/config/environment';

+const MAPBOX_API = 'https://api.mapbox.com/styles/v1/mapbox/streets-v11/static';
+const TOMTOM_API = 'https://api.tomtom.com/map/1/staticimage';
+
export default class Map extends Component {
+ get src() {
+ let { lng, lat, width, height, zoom } = this.args;
+
+ let coordinates = `${lng},${lat},${zoom}`;
+ let dimensions = `${width}x${height}`;
+ let accessToken = `access_token=${this.token}`;
+ let coordinates = `&zoom=${zoom}&center=${lng},${lat}`;
+ let dimensions = `&width=${width}&height=${height}`;
+ let accessToken = `?key=${this.token}`;
+
+ return `${MAPBOX_API}/${coordinates}/${dimensions}@2x?${accessToken}`;
+ return `${TOMTOM_API}${accessToken}${coordinates}${dimensions}`;
+ }
+
get token() {
@@ -13,3 +25,3 @@ export default class Map extends Component {
...attributes
- src="https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/{{@lng}},{{@lat}},{{@zoom}}/{{@width}}x{{@height}}@2x?access_token={{this.token}}"
- src="https://api.tomtom.com/map/1/staticimage?key={{this.token}}&zoom={{@zoom}}&center={{@lng}},{{@lat}}&width={{@width}}&height={{@height}}"
+ src={{this.src}}
width={{@width}} height={{@height}}
```
Expand Down Expand Up @@ -472,3 +466,4 @@ npm start
```run:checkpoint cwd=super-rentals
Chapter 7
```

Loading