Skip to content
Open
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions docs/angular/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ This sets up the root of your application, using Ionic's `ion-app` and `ion-rout
Routes are defined in `app.routes.ts`:

```ts title="src/app/app.routes.ts"
import { Routes } from '@angular/router';
import type { Routes } from '@angular/router';

export const routes: Routes = [
{
Expand Down Expand Up @@ -382,7 +382,7 @@ export class NewPage implements OnInit {

ngOnInit() {}

scrollToBottom = () => {
scrollToBottom = (): void => {
this.content.scrollToBottom(300);
};
}
Expand Down
31 changes: 28 additions & 3 deletions docs/angular/your-first-app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular';
// CHANGE: Add the following import
import { defineCustomElements } from '@ionic/pwa-elements/loader';

import { routes } from './app/app.routes';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';

// CHANGE: Call the element loader before the `bootstrapApplication` call
defineCustomElements(window);
Expand Down Expand Up @@ -195,11 +195,11 @@ We put the visual aspects of our app into `<ion-content>`. In this case, it’s
```html
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>Photo Gallery</ion-title>
<ion-title> Photo Gallery </ion-title>
</ion-toolbar>
</ion-header>

<ion-content>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Photo Gallery</ion-title>
Expand Down Expand Up @@ -243,4 +243,29 @@ Next, open `src/app/tabs/tabs.page.html`. Change the label to "Photos" and the `
</ion-tabs>
```

Then open `src/app/tabs/tabs.page.ts` and register the `images` icon in place of `ellipse`, so the new icon can display:

```ts
import { Component, EnvironmentInjector, inject } from '@angular/core';
import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/angular';
import { addIcons } from 'ionicons';
// CHANGE: Update import
import { triangle, images, square } from 'ionicons/icons';

@Component({
selector: 'app-tabs',
templateUrl: 'tabs.page.html',
styleUrls: ['tabs.page.scss'],
imports: [IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel],
})
export class TabsPage {
public environmentInjector = inject(EnvironmentInjector);

constructor() {
// CHANGE: Register the `images` icon instead of `ellipse`
addIcons({ triangle, images, square });
}
}
```

That’s just the start of all the cool things we can do with Ionic. Up next, implement camera taking functionality on the web, then build it for iOS and Android.
29 changes: 15 additions & 14 deletions docs/angular/your-first-app/2-taking-photos.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
})
export class PhotoService {
// CHANGE: Add the gallery method
public async addNewToGallery() {
public async addNewToGallery(): Promise<void> {
// Take a photo
const capturedPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100,
resultType: CameraResultType.Uri, // file-based data; provides best performance
source: CameraSource.Camera, // automatically take a new photo with the camera
quality: 100, // highest quality (0 to 100)
});
}
}
Expand Down Expand Up @@ -78,6 +78,7 @@ import {
// CHANGE: Register the camera icon used by the FAB
import { addIcons } from 'ionicons';
import { camera } from 'ionicons/icons';

// CHANGE: Import the PhotoService
import { PhotoService } from '../services/photo.service';

Expand All @@ -98,7 +99,7 @@ export class Tab2Page {
}

// CHANGE: Add `addPhotoToGallery()` method
addPhotoToGallery() {
addPhotoToGallery(): void {
this.photoService.addNewToGallery();
}
}
Expand Down Expand Up @@ -166,7 +167,7 @@ export class PhotoService {
// CHANGE: Add the `photos` signal
public photos = signal<UserPhoto[]>([]);

public async addNewToGallery() {
public async addNewToGallery(): Promise<void> {
// ...existing code...
}
}
Expand All @@ -176,12 +177,12 @@ Over in the `addNewToGallery` method, add the newly captured photo to the beginn

```ts
// CHANGE: Update `addNewToGallery()` method
public async addNewToGallery() {
public async addNewToGallery(): Promise<void> {
// Take a photo
const capturedPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100
resultType: CameraResultType.Uri, // file-based data; provides best performance
source: CameraSource.Camera, // automatically take a new photo with the camera
quality: 100, // highest quality (0 to 100)
});

// CHANGE: Add the new photo to the front of the photos signal
Expand All @@ -207,12 +208,12 @@ import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
export class PhotoService {
public photos = signal<UserPhoto[]>([]);

public async addNewToGallery() {
public async addNewToGallery(): Promise<void> {
// Take a photo
const capturedPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100,
resultType: CameraResultType.Uri, // file-based data; provides best performance
source: CameraSource.Camera, // automatically take a new photo with the camera
quality: 100, // highest quality (0 to 100)
});

this.photos.update((photos) => [
Expand Down
21 changes: 11 additions & 10 deletions docs/angular/your-first-app/3-saving-photos.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ We can use this new method immediately in `addNewToGallery()`.

```ts
import { Injectable, signal } from '@angular/core';
import { Camera, CameraResultType, CameraSource, Photo } from '@capacitor/camera';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import type { Photo } from '@capacitor/camera';

@Injectable({
providedIn: 'root',
Expand All @@ -56,12 +57,12 @@ export class PhotoService {
public photos = signal<UserPhoto[]>([]);

// CHANGE: Update the `addNewToGallery()` method
public async addNewToGallery() {
public async addNewToGallery(): Promise<void> {
// Take a photo
const capturedPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100,
resultType: CameraResultType.Uri, // file-based data; provides best performance
source: CameraSource.Camera, // automatically take a new photo with the camera
quality: 100, // highest quality (0 to 100)
});

// CHANGE: Add `savedImageFile`
Expand Down Expand Up @@ -93,7 +94,7 @@ Then, pass the data to the Filesystem's `writeFile` method. Recall that we displ
Create a new helper method, `base64FromPath()`, to implement the necessary logic for running on the web:

```ts
import { Injectable } from '@angular/core';
import { Injectable, signal } from '@angular/core';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import type { Photo } from '@capacitor/camera';
// CHANGE: Add import
Expand Down Expand Up @@ -164,12 +165,12 @@ import { Filesystem, Directory } from '@capacitor/filesystem';
export class PhotoService {
public photos = signal<UserPhoto[]>([]);

public async addNewToGallery() {
public async addNewToGallery(): Promise<void> {
// Take a photo
const capturedPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100,
resultType: CameraResultType.Uri, // file-based data; provides best performance
source: CameraSource.Camera, // automatically take a new photo with the camera
quality: 100, // highest quality (0 to 100)
});

// Save the picture and add it to photo collection
Expand Down
40 changes: 21 additions & 19 deletions docs/angular/your-first-app/4-loading-photos.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class PhotoService {
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.

```ts
import { Injectable } from '@angular/core';
import { Injectable, signal } from '@angular/core';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import type { Photo } from '@capacitor/camera';
import { Filesystem, Directory } from '@capacitor/filesystem';
Expand All @@ -47,12 +47,12 @@ export class PhotoService {
// ...existing code...

// CHANGE: Update `addNewToGallery()` method
public async addNewToGallery() {
public async addNewToGallery(): Promise<void> {
// Take a photo
const capturedPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100,
resultType: CameraResultType.Uri, // file-based data; provides best performance
source: CameraSource.Camera, // automatically take a new photo with the camera
quality: 100, // highest quality (0 to 100)
});

const savedImageFile = await this.savePicture(capturedPhoto);
Expand Down Expand Up @@ -82,7 +82,7 @@ export class PhotoService {
// ...existing code...

// CHANGE: Add the method to load the photo data
public async loadSaved() {
public async loadSaved(): Promise<void> {
// Retrieve cached photo array data
const { value: photoList } = await Preferences.get({ key: this.PHOTO_STORAGE });
this.photos.set((photoList ? JSON.parse(photoList) : []) as UserPhoto[]);
Expand All @@ -97,21 +97,21 @@ export class PhotoService {
// ...existing code...

// CHANGE: Update the `loadSaved()` method
public async loadSaved() {
public async loadSaved(): Promise<void> {
// Retrieve cached photo array data
const { value: photoList } = await Preferences.get({ key: this.PHOTO_STORAGE });
const photos = (photoList ? JSON.parse(photoList) : []) as UserPhoto[];

// CHANGE: Display the photo by reading into base64 format
for (const photo of photos) {
// Read each saved photo's data from the Filesystem
const file = await Filesystem.readFile({
const readFile = await Filesystem.readFile({
path: photo.filepath,
directory: Directory.Data,
});

// Web platform only: Load the photo as base64 data
photo.webviewPath = `data:image/jpeg;base64,${file.data}`;
photo.webviewPath = `data:image/jpeg;base64,${readFile.data}`;
}

// CHANGE: Set the signal so the gallery view updates
Expand All @@ -137,12 +137,12 @@ export class PhotoService {

private PHOTO_STORAGE: string = 'photos';

public async addNewToGallery() {
public async addNewToGallery(): Promise<void> {
// Take a photo
const capturedPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100,
resultType: CameraResultType.Uri, // file-based data; provides best performance
source: CameraSource.Camera, // automatically take a new photo with the camera
quality: 100, // highest quality (0 to 100)
});

// Save the picture and add it to photo collection
Expand Down Expand Up @@ -192,20 +192,20 @@ export class PhotoService {
});
}

public async loadSaved() {
public async loadSaved(): Promise<void> {
// Retrieve cached photo array data
const { value: photoList } = await Preferences.get({ key: this.PHOTO_STORAGE });
const photos = (photoList ? JSON.parse(photoList) : []) as UserPhoto[];

for (const photo of photos) {
// Read each saved photo's data from the Filesystem
const file = await Filesystem.readFile({
const readFile = await Filesystem.readFile({
path: photo.filepath,
directory: Directory.Data,
});

// Web platform only: Load the photo as base64 data
photo.webviewPath = `data:image/jpeg;base64,${file.data}`;
photo.webviewPath = `data:image/jpeg;base64,${readFile.data}`;
}

this.photos.set(photos);
Expand All @@ -223,7 +223,8 @@ Our `PhotoService` can now load the saved images, but we'll need to update `tab2
Update `tab2.page.ts` to look like the following:

```ts
import { Component, OnInit, inject } from '@angular/core';
import type { OnInit } from '@angular/core';
import { Component, inject } from '@angular/core';
import {
IonHeader,
IonToolbar,
Expand All @@ -238,6 +239,7 @@ import {
} from '@ionic/angular';
import { addIcons } from 'ionicons';
import { camera } from 'ionicons/icons';

import { PhotoService } from '../services/photo.service';

@Component({
Expand All @@ -254,11 +256,11 @@ export class Tab2Page implements OnInit {
}

// CHANGE: Add call to `loadSaved()` when navigating to the Photos tab
async ngOnInit() {
async ngOnInit(): Promise<void> {
await this.photoService.loadSaved();
}

addPhotoToGallery() {
addPhotoToGallery(): void {
this.photoService.addNewToGallery();
}
}
Expand Down
Loading
Loading