Skip to content

Commit 49210d3

Browse files
committed
docs(angular): update your first app pages
1 parent dc6764c commit 49210d3

File tree

8 files changed

+170
-126
lines changed

8 files changed

+170
-126
lines changed

docs/angular/your-first-app.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ sidebar_label: Build Your First App
44
---
55

66
<head>
7-
<title>Build Your First Ionic Mobile App: Angular Development Tutorial</title>
7+
<title>Build Your First Ionic Mobile App with Angular | Ionic Capacitor Camera</title>
88
<meta
99
name="description"
10-
content="Ionic's single codebase builds for any platform using just HTML, CSS, & JavaScript. Develop your first mobile app with our step-by-step Angular tutorial."
10+
content="This Angular tutorial teaches the fundamentals of Ionic app development by creating a realistic app step-by-step. Learn to run your first Ionic app with Angular."
1111
/>
1212
</head>
1313

14+
# Your First Ionic App: Angular
15+
1416
The great thing about Ionic is that with one codebase, you can build for any platform using just HTML, CSS, and JavaScript. Follow along as we learn the fundamentals of Ionic app development by creating a realistic app step by step.
1517

1618
Here’s the finished app running on all 3 platforms:
@@ -38,7 +40,7 @@ Highlights include:
3840
- Deployed as a native iOS and Android mobile app using [Capacitor](https://capacitorjs.com), Ionic's official native app runtime.
3941
- Photo Gallery functionality powered by the Capacitor [Camera](../native/camera.md), [Filesystem](../native/filesystem.md), and [Preferences](../native/preferences.md) APIs.
4042

41-
Find the complete app code referenced in this guide [on GitHub](https://github.com/ionic-team/photo-gallery-capacitor-ng).
43+
Find the [complete app code](https://github.com/ionic-team/tutorial-photo-gallery-angular) referenced in this guide on GitHub.
4244

4345
## Download Required Tools
4446

@@ -70,7 +72,7 @@ Consider setting up npm to operate globally without elevated permissions. See [R
7072

7173
## Create an App
7274

73-
Next, create an Ionic Angular app that uses the Tabs starter template and adds Capacitor for native functionality:
75+
Next, create an Ionic Angular app that uses the "Tabs" starter template and adds Capacitor for native functionality:
7476

7577
```shell
7678
ionic start photo-gallery tabs --type=angular --capacitor
@@ -194,7 +196,7 @@ We put the visual aspects of our app into `<ion-content>`. In this case, it’s
194196
</ion-content>
195197
```
196198

197-
Next, open `src/app/tabs/tabs.page.html`. Change the label to Photos and the `ellipse` icon to `images` for the middle tab button.
199+
Next, open `src/app/tabs/tabs.page.html`. Change the label to "Photos" and the `ellipse` icon to `images` for the middle tab button.
198200

199201
```html
200202
<ion-tabs>

docs/angular/your-first-app/2-taking-photos.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ sidebar_label: Taking Photos
44
---
55

66
<head>
7-
<title>Build Camera API for iOS, Android & Web | Ionic Capacitor Camera</title>
7+
<title>Take Photos with Camera API for iOS, Android & Web with Angular | Ionic Capacitor Camera</title>
88
<meta
99
name="description"
1010
content="Add the ability to take photos with your device's camera using the Ionic Capacitor Camera API for mobile iOS, Android, and the web. Learn how here."
1111
/>
1212
</head>
1313

14+
# Taking Photos with the Camera
15+
1416
Now for the fun part - adding the ability to take photos with the device’s camera using the Capacitor [Camera API](../../native/camera.md). We’ll begin with building it for the web, then make some small tweaks to make it work on mobile (iOS and Android).
1517

1618
## Photo Service
@@ -21,7 +23,7 @@ All Capacitor logic (Camera usage and other native features) will be encapsulate
2123
ionic g service services/photo.service
2224
```
2325

24-
Open the new `services/photo.service.ts` file, and let’s add the logic that will power the camera functionality. First, import Capacitor dependencies and get references to the Camera, Filesystem, and Storage plugins:
26+
Open the new `services/photo.service.ts` file, and let’s add the logic that will power the camera functionality. First, import Capacitor dependencies and get references to the `Camera`, `Filesystem`, and `Storage` plugins:
2527

2628
```ts
2729
import { Injectable } from '@angular/core';
@@ -36,7 +38,7 @@ import { Preferences } from '@capacitor/preferences';
3638
export class PhotoService {}
3739
```
3840

39-
Next, define a new class method, `addNewToGallery`, that will contain the core logic to take a device photo and save it to the filesystem. Let’s start by opening the device camera:
41+
Next, define a new class method, `addNewToGallery()`, that will contain the core logic to take a device photo and save it to the filesystem. Let’s start by opening the device camera.
4042

4143
```ts
4244
import { Injectable } from '@angular/core';
@@ -57,7 +59,7 @@ export class PhotoService {
5759
}
5860
```
5961

60-
Notice the magic here: there's no platform-specific code (web, iOS, or Android)! The Capacitor Camera plugin abstracts that away for us, leaving just one method call - `Camera.getPhoto()` - that will open up the device's camera and allow us to take photos.
62+
Notice the magic here: there's no platform-specific code (web, iOS, or Android)! The Capacitor Camera plugin abstracts that away for us, leaving just one method call - `getPhoto()` - that will open up the device's camera and allow us to take photos.
6163

6264
Next, in `tab2.page.ts`, import the `PhotoService` class and add a method to call its `addNewToGallery` method.
6365

@@ -127,7 +129,7 @@ export class PhotoService {
127129
// Same old code from before.
128130
}
129131

130-
// CHANGE: Add the interface.
132+
// CHANGE: Add the `UserPhoto` interface.
131133
export interface UserPhoto {
132134
filepath: string;
133135
webviewPath?: string;
@@ -138,7 +140,7 @@ Above the `addNewToGallery()` method, define an array of `UserPhoto`, which will
138140

139141
```ts
140142
export class PhotoService {
141-
// CHANGE: Add the photos array.
143+
// CHANGE: Add the `photos` array.
142144
public photos: UserPhoto[] = [];
143145

144146
public async addNewToGallery() {
@@ -152,6 +154,7 @@ Over in the `addNewToGallery` method, add the newly captured photo to the beginn
152154
```ts
153155
// CHANGE: Update `addNewToGallery()` method.
154156
public async addNewToGallery() {
157+
// Take a photo
155158
const capturedPhoto = await Camera.getPhoto({
156159
resultType: CameraResultType.Uri,
157160
source: CameraSource.Camera,

docs/angular/your-first-app/3-saving-photos.md

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ title: Saving Photos to the Filesystem
33
sidebar_label: Saving Photos
44
---
55

6+
<head>
7+
<title>Saving Photos to the Filesystem with Angular | Ionic Capacitor Camera</title>
8+
<meta
9+
name="description"
10+
content="We’re now able to take multiple photos and display them in a photo gallery. Learn how to save these photos to the filesystem using the Ionic Capacitor Filesystem API."
11+
/>
12+
</head>
13+
614
# Saving Photos to the Filesystem
715

816
We’re now able to take multiple photos and display them in a photo gallery on the second tab of our app. These photos, however, are not currently being stored permanently, so when the app is closed, they will be deleted.
@@ -23,7 +31,7 @@ import { Preferences } from '@capacitor/preferences';
2331
export class PhotoService {
2432
// Same old code from before.
2533

26-
// CHANGE: Add the `savePicture` method.
34+
// CHANGE: Add the `savePicture()` method.
2735
private async savePicture(photo: Photo) {
2836
return {
2937
filepath: 'soon...',
@@ -52,7 +60,7 @@ import { Preferences } from '@capacitor/preferences';
5260
export class PhotoService {
5361
public photos: UserPhoto[] = [];
5462

55-
// CHANGE: Update `addNewToGallery()` method.
63+
// CHANGE: Update the `addNewToGallery()` method.
5664
public async addNewToGallery() {
5765
// Take a photo
5866
const capturedPhoto = await Camera.getPhoto({
@@ -61,7 +69,7 @@ export class PhotoService {
6169
quality: 100,
6270
});
6371

64-
// CHANGE: Add `savedImageFile` to save the picture and add it to photo collection.
72+
// CHANGE: Add `savedImageFile`.
6573
// Save the picture and add it to photo collection
6674
const savedImageFile = await this.savePicture(capturedPhoto);
6775

@@ -83,11 +91,11 @@ export interface UserPhoto {
8391
}
8492
```
8593

86-
We'll use the Capacitor [Filesystem API](../../native/filesystem.md) to save the photo. First, convert the photo to base64 format using a helper method we'll define: `readAsBase64()`.
94+
We'll use the Capacitor [Filesystem API](../../native/filesystem.md) to save the photo. First, convert the photo to base64 format.
8795

8896
Then, pass the data to the Filesystem's `writeFile` method. Recall that we display photos by setting the image's source path (`src`) to the `webviewPath` property. So, set the `webviewPath` and return the new `Photo` object.
8997

90-
The `readAsBase64()` method is necessary because it isolates a small amount of platform-specific logic (more on that soon). For now, create two new helper methods, `readAsBase64()` and `convertBlobToBase64()`, to implement the necessary logic for running on the web.
98+
For now, create a new helper method, `convertBlobToBase64()`, to implement the necessary logic for running on the web.
9199

92100
```ts
93101
import { Injectable } from '@angular/core';
@@ -101,10 +109,12 @@ import { Preferences } from '@capacitor/preferences';
101109
export class PhotoService {
102110
// Same old code from before.
103111

104-
// CHANGE: Update the `savePicture` method.
112+
// CHANGE: Update the `savePicture()` method.
105113
private async savePicture(photo: Photo) {
106-
// Convert photo to base64 format, required by Filesystem API to save
107-
const base64Data = await this.readAsBase64(photo);
114+
// Fetch the photo, read as a blob, then convert to base64 format
115+
const response = await fetch(photo.webPath!);
116+
const blob = await response.blob();
117+
const base64Data = (await this.convertBlobToBase64(blob)) as string;
108118

109119
// Write the file to the data directory
110120
const fileName = Date.now() + '.jpeg';
@@ -122,15 +132,6 @@ export class PhotoService {
122132
};
123133
}
124134

125-
// CHANGE: Add the `readAsBase64` method.
126-
private async readAsBase64(photo: Photo) {
127-
// Fetch the photo, read as a blob, then convert to base64 format
128-
const response = await fetch(photo.webPath!);
129-
const blob = await response.blob();
130-
131-
return (await this.convertBlobToBase64(blob)) as string;
132-
}
133-
134135
// CHANGE: Add the `convertBlobToBase64` method.
135136
private convertBlobToBase64(blob: Blob) {
136137
return new Promise((resolve, reject) => {
@@ -179,8 +180,10 @@ export class PhotoService {
179180
}
180181

181182
private async savePicture(photo: Photo) {
182-
// Convert photo to base64 format, required by Filesystem API to save
183-
const base64Data = await this.readAsBase64(photo);
183+
// Fetch the photo, read as a blob, then convert to base64 format
184+
const response = await fetch(photo.webPath!);
185+
const blob = await response.blob();
186+
const base64Data = (await this.convertBlobToBase64(blob)) as string;
184187

185188
// Write the file to the data directory
186189
const fileName = Date.now() + '.jpeg';
@@ -198,14 +201,6 @@ export class PhotoService {
198201
};
199202
}
200203

201-
private async readAsBase64(photo: Photo) {
202-
// Fetch the photo, read as a blob, then convert to base64 format
203-
const response = await fetch(photo.webPath!);
204-
const blob = await response.blob();
205-
206-
return (await this.convertBlobToBase64(blob)) as string;
207-
}
208-
209204
private convertBlobToBase64(blob: Blob) {
210205
return new Promise((resolve, reject) => {
211206
const reader = new FileReader();
@@ -226,6 +221,4 @@ export interface UserPhoto {
226221

227222
Obtaining the camera photo as base64 format on the web appears to be a bit trickier than on mobile. In reality, we’re just using built-in web APIs: [fetch()](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) as a neat way to read the file into blob format, then FileReader’s [readAsDataURL()](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL) to convert the photo blob to base64.
228223

229-
There we go! Each time a new photo is taken, it’s now automatically saved to the filesystem.
230-
231-
Next up, we'll load and display our saved images.
224+
There we go! Each time a new photo is taken, it’s now automatically saved to the filesystem. Next up, we'll load and display our saved images.

docs/angular/your-first-app/4-loading-photos.md

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ title: Loading Photos from the Filesystem
33
sidebar_label: Loading Photos
44
---
55

6+
<head>
7+
<title>Loading Photos from the Filesystem with Angular | Ionic Capacitor Camera</title>
8+
<meta
9+
name="description"
10+
content="We’ve implemented photo taking and saving to the filesystem, now learn how Ionic leverages Capacitor Preferences API for loading our photos in a key-value store."
11+
/>
12+
</head>
13+
614
# Loading Photos from the Filesystem
715

816
We’ve implemented photo taking and saving to the filesystem. There’s one last piece of functionality missing: the photos are stored in the filesystem, but we need a way to save pointers to each file so that they can be displayed again in the photo gallery.
@@ -11,7 +19,7 @@ Fortunately, this is easy: we’ll leverage the Capacitor [Preferences API](../.
1119

1220
## Preferences API
1321

14-
Open `photo.service.ts` and begin by defining a new property in the `PhotoService` class that will act as the key for the store:
22+
Open `photo.service.ts` and begin by defining a new property in the `PhotoService` class that will act as the key for the store.
1523

1624
```ts
1725
export class PhotoService {
@@ -24,7 +32,7 @@ export class PhotoService {
2432
}
2533
```
2634

27-
Next, at the end of the `addNewToGallery` method, add a call to `Preferences.set()` to save the `photos` array. By adding it here, the `photos` array is stored each time a new photo is taken. This way, it doesn’t matter when the app user closes or switches to a different app - all photo data is saved.
35+
Next, at the end of the `addNewToGallery()` method, add a call to `Preferences.set()` to save the `photos` array. By adding it here, the `photos` array is stored each time a new photo is taken. This way, it doesn’t matter when the app user closes or switches to a different app - all photo data is saved.
2836

2937
```ts
3038
public async addNewToGallery() {
@@ -56,8 +64,8 @@ export class PhotoService {
5664
// CHANGE: Add the method to load the photo data.
5765
public async loadSaved() {
5866
// Retrieve cached photo array data
59-
const { value } = await Preferences.get({ key: this.PHOTO_STORAGE });
60-
this.photos = (value ? JSON.parse(value) : []) as UserPhoto[];
67+
const { value: photoList } = await Preferences.get({ key: this.PHOTO_STORAGE });
68+
this.photos = (photoList ? JSON.parse(photoList) : []) as UserPhoto[];
6169
}
6270
}
6371
```
@@ -71,13 +79,13 @@ export class PhotoService {
7179
// CHANGE: Update the `loadSaved` method.
7280
public async loadSaved() {
7381
// Retrieve cached photo array data
74-
const { value } = await Preferences.get({ key: this.PHOTO_STORAGE });
75-
this.photos = (value ? JSON.parse(value) : []) as UserPhoto[];
82+
const { value: photoList } = await Preferences.get({ key: this.PHOTO_STORAGE });
83+
this.photos = (photoList ? JSON.parse(photoList) : []) as UserPhoto[];
7684

7785
// CHANGE: Display the photo by reading into base64 format.
7886
for (let photo of this.photos) {
7987
// Read each saved photo's data from the Filesystem
80-
const readFile = await Filesystem.readFile({
88+
const file = await Filesystem.file({
8189
path: photo.filepath,
8290
directory: Directory.Data,
8391
});
@@ -124,8 +132,10 @@ export class PhotoService {
124132
}
125133

126134
private async savePicture(photo: Photo) {
127-
// Convert photo to base64 format, required by Filesystem API to save
128-
const base64Data = await this.readAsBase64(photo);
135+
// Fetch the photo, read as a blob, then convert to base64 format
136+
const response = await fetch(photo.webPath!);
137+
const blob = await response.blob();
138+
const base64Data = (await this.convertBlobToBase64(blob)) as string;
129139

130140
// Write the file to the data directory
131141
const fileName = Date.now() + '.jpeg';
@@ -143,14 +153,6 @@ export class PhotoService {
143153
};
144154
}
145155

146-
private async readAsBase64(photo: Photo) {
147-
// Fetch the photo, read as a blob, then convert to base64 format
148-
const response = await fetch(photo.webPath!);
149-
const blob = await response.blob();
150-
151-
return (await this.convertBlobToBase64(blob)) as string;
152-
}
153-
154156
private convertBlobToBase64(blob: Blob) {
155157
return new Promise((resolve, reject) => {
156158
const reader = new FileReader();
@@ -164,8 +166,8 @@ export class PhotoService {
164166

165167
public async loadSaved() {
166168
// Retrieve cached photo array data
167-
const { value } = await Preferences.get({ key: this.PHOTO_STORAGE });
168-
this.photos = (value ? JSON.parse(value) : []) as UserPhoto[];
169+
const { value: photoList } = await Preferences.get({ key: this.PHOTO_STORAGE });
170+
this.photos = (photoList ? JSON.parse(photoList) : []) as UserPhoto[];
169171
}
170172
}
171173

0 commit comments

Comments
 (0)