Skip to content

Commit d435e7e

Browse files
aredshawijlee2
andauthored
Add links for learning more (part 4 of 4) - New (#167)
* first run through-no links given * URL changes * More link fixes * more link fixes * Slight URL modifications * Update src/markdown/tutorial/part-2/10-service-injection.md * Update src/markdown/tutorial/part-2/11-ember-data.md * Update src/markdown/tutorial/part-2/11-ember-data.md * Update src/markdown/tutorial/part-2/12-provider-components.md * Update src/markdown/tutorial/part-2/12-provider-components.md * Update src/markdown/tutorial/part-2/10-service-injection.md * Update src/markdown/tutorial/part-2/10-service-injection.md * Update src/markdown/tutorial/part-2/10-service-injection.md * Update src/markdown/tutorial/part-2/11-ember-data.md * Update src/markdown/tutorial/part-2/11-ember-data.md * Update src/markdown/tutorial/part-2/11-ember-data.md * Update src/markdown/tutorial/part-2/11-ember-data.md * Update src/markdown/tutorial/part-2/11-ember-data.md * minor fix * Update src/markdown/tutorial/part-2/11-ember-data.md * Update src/markdown/tutorial/part-2/11-ember-data.md * Update src/markdown/tutorial/part-2/11-ember-data.md * Update src/markdown/tutorial/part-2/12-provider-components.md Co-authored-by: Aaron Redshaw <[email protected]> Co-authored-by: Isaac Lee <[email protected]>
1 parent 3460029 commit d435e7e

File tree

3 files changed

+20
-20
lines changed

3 files changed

+20
-20
lines changed

src/markdown/tutorial/part-2/10-service-injection.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ Whew! Let's look at the JavaScript class next.
118118
}
119119
```
120120

121-
The key functionality of this class is to build the appropriate URL for the Twitter Web Intent API, which is exposed to the template via the `this.shareURL` getter. It mainly involves "gluing together" the component's arguments and setting the appropriate query params on the resulting URL. Conveniently, the browser provides a handy [`URL` class][TODO: link to URL class] that handles escaping and joining of query params for us.
121+
The key functionality of this class is to build the appropriate URL for the Twitter Web Intent API, which is exposed to the template via the `this.shareURL` getter. It mainly involves "gluing together" the component's arguments and setting the appropriate query params on the resulting URL. Conveniently, the browser provides a handy [`URL` class](https://javascript.info/url) that handles escaping and joining of query params for us.
122122

123123
The other notable functionality of this class has to do with getting the current page's URL and automatically adding it to the Twitter Intent URL. To accomplish this, we defined a `currentURL` getter that simply used the browser's global [`Location` object](https://developer.mozilla.org/en-US/docs/Web/API/Window/location), which we could access at `window.location`. Among other things, it has a `href` property (`window.location.href`) that reports the current page's URL.
124124

@@ -205,13 +205,13 @@ Looking at the failure closely, the problem seems to be that the component had c
205205

206206
This brings up an interesting question – why does the `currentURL()` test helper not have the same problem? In our test, we have been writing assertions like `assert.equal(currentURL(), '/about');`, and those assertions did not fail.
207207

208-
It turns out that this is something Ember's router handled for us. In an Ember app, the router is responsible for handling navigation and maintaining the URL. For example, when you click on a `<LinkTo>` component, it will ask the router to execute a *[route transition][TODO: link to route transition]*. Normally, the router is set up to update the browser's address bar whenever it transitions into a new route. That way, your users will be able to use the browser's back button and bookmark functionality just like any other webpage.
208+
It turns out that this is something Ember's router handled for us. In an Ember app, the router is responsible for handling navigation and maintaining the URL. For example, when you click on a `<LinkTo>` component, it will ask the router to execute a *[route transition](../../../routing/preventing-and-retrying-transitions/)*. Normally, the router is set up to update the browser's address bar whenever it transitions into a new route. That way, your users will be able to use the browser's back button and bookmark functionality just like any other webpage.
209209

210210
However, during tests, the router is configured to maintain the "logical" URL internally, without updating the browser's address bar and history entries. This way, the router won't confuse the browser and its back button with hundreds of history entries as you run through your tests. The `currentURL()` taps into this piece of internal state in the router, instead of checking directly against the actual URL in the address bar using `window.location.href`.
211211

212212
## The Router Service
213213

214-
To fix our problem, we would need to do the same. Ember exposes this internal state through the *[router service][TODO: link to router service]*, which we can *[inject][TODO: link to inject]* into our component:
214+
To fix our problem, we would need to do the same. Ember exposes this internal state through the *[router service](https://api.emberjs.com/ember/release/classes/RouterService)*, which we can *[inject](../../../services/#toc_accessing-services)* into our component:
215215

216216
```run:file:patch lang=js cwd=super-rentals filename=app/components/share-button.js
217217
@@ -1 +1,2 @@
@@ -309,7 +309,7 @@ We will take advantage of this capability in our component test:
309309
});
310310
```
311311
312-
In this component test, we *[registered][TODO: link to register]* our own router service with Ember in the `beforeEach` hook. When our component is rendered and requests the router service to be injected, it will get an instance of our `MockRouterService` instead of the built-in router service.
312+
In this component test, we *[registered](../../../applications/dependency-injection/#toc_factory-registrations)* our own router service with Ember in the `beforeEach` hook. When our component is rendered and requests the router service to be injected, it will get an instance of our `MockRouterService` instead of the built-in router service.
313313
314314
This is a pretty common testing technique called *mocking* or *stubbing*. Our `MockRouterService` implements the same interface as the built-in router service – the part that we care about anyway; which is that it has a `currentURL` property that reports the current "logical" URL. This allows us to fix the URL at a pre-determined value, making it possible to easily test our component without having to navigate to a different page. As far as our component can tell, we are currently on the page `/foo/bar/baz?some=page#anchor`, because that's the result it would get when querying the router service.
315315

src/markdown/tutorial/part-2/11-ember-data.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ A while back, we added the `rental` route. If memory serves us well, we didn't d
2929

3030
This duplication incurred a bit of *[technical debt][TODO: link to technical debt]* for us, making our code base harder to maintain in the long run. For example, if we wanted to change something about how our data-fetching logic worked, we'd have to change it in *both* the `index` and `rental` routes. If we changed things in one place, but forgot about the other spot, we could end up with really subtle bugs in our app! Yikes!
3131

32-
Chances are, as we keep working on this app, we will need to add more routes that fetch data from the server. Since all of our server's API endpoints follow the [JSON:API][TODO: link to JSON:API] format, we'd have to keep copying this boilerplate for every single new route we add to the app!
32+
Chances are, as we keep working on this app, we will need to add more routes that fetch data from the server. Since all of our server's API endpoints follow the [JSON:API](https://jsonapi.org/) format, we'd have to keep copying this boilerplate for every single new route we add to the app!
3333

34-
Fortunately, we're not going to do any of that. As it turns out, there's a much better solution here: we can use Ember Data! As its name implies, [Ember Data][TODO: link to Ember Data] is a library that helps manage data and *[application state][TODO: link to application state]* in Ember applications.
34+
Fortunately, we're not going to do any of that. As it turns out, there's a much better solution here: we can use Ember Data! As its name implies, [Ember Data](../../../models/) is a library that helps manage data and *[application state][TODO: link to application state]* in Ember applications.
3535

3636
There's a lot to learn about Ember Data, but let's start by uncovering features that help with our immediate problem.
3737

3838
## Ember Data Models
3939

40-
Ember Data is built around the idea of organizing your app's data into *[model objects][TODO: link to models]*. These objects represent units of information that our application presents to the user. For example, the rental property data we have been working with would be a good candidate.
40+
Ember Data is built around the idea of organizing your app's data into *[model objects](../../../models/defining-models/)*. These objects represent units of information that our application presents to the user. For example, the rental property data we have been working with would be a good candidate.
4141

4242
Enough talking, why don't we give that a try!
4343

@@ -70,7 +70,7 @@ export default class RentalModel extends Model {
7070
}
7171
```
7272

73-
Here, we created a `RentalModel` class that extends Ember Data's `Model` superclass. When fetching the listing data from the server, each individual rental property will be represented by an instance (also known as a *[record][TODO: link to record]*) of our `RentalModel` class.
73+
Here, we created a `RentalModel` class that extends Ember Data's `Model` superclass. When fetching the listing data from the server, each individual rental property will be represented by an instance (also known as a *[record](../../../models/finding-records/)* of our `RentalModel` class.
7474

7575
We used the `@attr` decorator to declare the attributes of a rental property. These attributes correspond directly to the `attributes` data we expect the server to provide in its responses:
7676

@@ -147,9 +147,9 @@ The generator created some boilerplate code for us, which serves as a pretty goo
147147
});
148148
```
149149
150-
This model test is also known as a *[unit test][TODO: link to unit test]*. Unlike any of the other tests that we've written thus far, this test doesn't actually *render* anything. It just instantiates the rental model object and tests the model object directly, manipulating its attributes and asserting their value.
150+
This model test is also known as a *[unit test](../../../testing/testing-models/)*. Unlike any of the other tests that we've written thus far, this test doesn't actually *render* anything. It just instantiates the rental model object and tests the model object directly, manipulating its attributes and asserting their value.
151151
152-
It is worth pointing out that Ember Data provides a *[`store` service][TODO: link to Ember Data store]*, also known as the Ember Data store. In our test, we used the `this.owner.lookup('service:store')` API to get access to the Ember Data store. The store provides a `createRecord` method to instantiate our model object for us.
152+
It is worth pointing out that Ember Data provides a `store` *[service](../../../services/)*, also known as the Ember Data store. In our test, we used the `this.owner.lookup('service:store')` API to get access to the Ember Data store. The store provides a `createRecord` method to instantiate our model object for us.
153153
154154
Running the tests in the browser confirms that everything is working as intended:
155155
@@ -229,15 +229,15 @@ Alright, now that we have our model set up, it's time to refactor our route hand
229229
-
230230
- return { id, type, ...attributes };
231231
+ async model(params) {
232-
+ return this.store.find('rental', params.rental_id);
232+
+ return this.store.findRecord('rental', params.rental_id);
233233
}
234234
```
235235
236236
Wow... that removed a lot of code! This is all possible thanks to the power of conventions!
237237
238238
## The Ember Data Store
239239
240-
As mentioned above, Ember Data provides a `store` service, which we can inject into our route using the `@service store;` declaration, making the Ember Data store available as `this.store`. It provides the `find` and `findAll` methods for loading records. Specifically, the [`find` method][TODO: link to find] takes a model type (`rental` in our case) and a model ID (for us, that would be `params.rental_id` from the URL) as arguments and fetches a single record from the store. On the other hand, the [`findAll` method][TODO: link to findAll] takes the model type as an argument and fetches all records of that type from the store.
240+
As mentioned above, Ember Data provides a `store` service, which we can inject into our route using the `@service store;` declaration, making the Ember Data store available as `this.store`. It provides the `find` and `findAll` methods for loading records. Specifically, the [`findRecord` method](../../../models/finding-records/#toc_retrieving-a-single-record) takes a model type (`rental` in our case) and a model ID (for us, that would be `params.rental_id` from the URL) as arguments and fetches a single record from the store. On the other hand, the [`findAll` method](../../../models/finding-records/#toc_retrieving-multiple-records) takes the model type as an argument and fetches all records of that type from the store.
241241
242242
The Ember Data store acts as a kind of intermediary between our app and the server; it does many important things, including caching the responses that were fetched from the server. If we request some records (instances of model classes) that we had *already* fetched from the server in the past, Ember Data's store ensures that we can access the records immediately, without having to fetch them again unnecessarily and wait for the server to respond. But, if we don't already have that response cached in our store, then it will go off and fetches it from the server. Pretty nice, right?
243243
@@ -259,7 +259,7 @@ Hm, okay, so we have to teach Ember Data to fetch data from the correct location
259259
260260
## Working with Adapters and Serializers
261261
262-
Ember Data uses an *[adapter][TODO: link to adapter]* and *[serializer][TODO: link to serializer]* architecture. Adapters deal with *how* and *where* Ember Data should fetch data from your servers, such as whether to use HTTP, HTTPS, WebSockets or local storage, as well as the URLs, headers and parameters to use for these requests. On the other hand, serializers are in charge of converting the data returned by the server into a format Ember Data can understand.
262+
Ember Data uses an *[adapter](../../../models/customizing-adapters/)* and *[serializer](../../../models/customizing-serializers/)* architecture. Adapters deal with *how* and *where* Ember Data should fetch data from your servers, such as whether to use HTTP, HTTPS, WebSockets or local storage, as well as the URLs, headers and parameters to use for these requests. On the other hand, serializers are in charge of converting the data returned by the server into a format Ember Data can understand.
263263
264264
The idea is that, provided that your backend exposes a *consistent* protocol and interchange format to access its data, we can write a single adapter-serializer pair to handle all data fetches for the entire application.
265265
@@ -288,16 +288,16 @@ export default class ApplicationSerializer extends JSONAPISerializer {
288288
289289
By convention, adapters are located at `app/adapters`. Furthermore, the adapter named `application` is called the *application adapter*, which will be used to fetch data for all models in our app.
290290
291-
Inside this newly created file, we defined an `ApplicationAdapter` class, inheriting from the built-in [`JSONAPIAdapter`][TODO: link to docs]. This allows us to inherit all the default JSON:API functionalities, while customizing the things that didn't work for us by default. Specifically:
291+
Inside this newly created file, we defined an `ApplicationAdapter` class, inheriting from the built-in [`JSONAPIAdapter`](https://api.emberjs.com/ember-data/release/classes/JSONAPIAdapter). This allows us to inherit all the default JSON:API functionalities, while customizing the things that didn't work for us by default. Specifically:
292292
293293
* Our resource URLs have an extra `/api` *namespace* prefix.
294294
* Our resource URLs have a `.json` extension at the end.
295295
296296
Adding a namespace prefix happens to be pretty common across Ember apps, so the `JSONAPIAdapter` has an API to do just that. All we need to do is to set the `namespace` property to the prefix we want, which is `api` in our case.
297297
298-
Adding the `.json` extension is a bit less common, and doesn't have a declarative configuration API of its own. Instead, we will need to *[override][TODO: link to override]* Ember Data's [`buildURL`][TODO: link to buildURL] method. Inside of `buildURL`, we will call `super.buildURL(...args)` to invoke the `JSONAPIAdapter` default implementation of `buildURL`. This will give us the URL that the adapter *would have built*, which would be something like `/api/rentals` and `/api/rentals/grand-old-mansion` after configuring the `namespace` above. All we have to do is to append `.json` to this URL and return it.
298+
Adding the `.json` extension is a bit less common, and doesn't have a declarative configuration API of its own. Instead, we will need to *[override][TODO: link to override]* Ember Data's [`buildURL`](https://api.emberjs.com/ember-data/release/classes/JSONAPIAdapter/methods/buildURL?anchor=buildURL) method. Inside of `buildURL`, we will call `super.buildURL(...args)` to invoke the `JSONAPIAdapter` default implementation of `buildURL`. This will give us the URL that the adapter *would have built*, which would be something like `/api/rentals` and `/api/rentals/grand-old-mansion` after configuring the `namespace` above. All we have to do is to append `.json` to this URL and return it.
299299
300-
Similarly, serializers are located at `app/serializers`. Adapters and serializers are always added together as a pair. We added an `application` adapter, so we also added a corresponding serializer to go with it as well. Since the JSON data returned by our server is JSON:API-compliant, the default [`JSONAPISerializer`][TODO: link to docs] work just fine for us without further customization.
300+
Similarly, serializers are located at `app/serializers`. Adapters and serializers are always added together as a pair. We added an `application` adapter, so we also added a corresponding serializer to go with it as well. Since the JSON data returned by our server is JSON:API-compliant, the default [`JSONAPISerializer`](https://api.emberjs.com/ember-data/release/classes/JSONAPISerializer) work just fine for us without further customization.
301301
302302
With our adapter and serializer in place, all our tests should pass again.
303303
@@ -326,7 +326,7 @@ visit http://localhost:4200/rentals/grand-old-mansion?deterministic
326326
wait .rental.detailed
327327
```
328328
329-
Ember Data offers many, many features (like managing the *relationships* between different models) and there's a lot more we can learn about it. For example, if your backend's have some inconsistencies across different endpoints, Ember Data allows you to define more specific, per-model adapters and serializers too! We are just scratching the surface here. If you want to learn more about Ember Data, check out [its own dedicated section][TODO: link to Ember Data] in the guides!
329+
Ember Data offers many, many features (like managing the *relationships* between different models) and there's a lot more we can learn about it. For example, if your backend's have some inconsistencies across different endpoints, Ember Data allows you to define more specific, per-model adapters and serializers too! We are just scratching the surface here. If you want to learn more about Ember Data, check out [its own dedicated section](../../../models/) in the guides!
330330
331331
```run:server:stop
332332
ember server

0 commit comments

Comments
 (0)