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
23 changes: 5 additions & 18 deletions docs/angular/your-first-app/2-taking-photos.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ import {
IonGrid,
IonRow,
IonCol,
IonImg,
IonFab,
IonFabButton,
IonIcon,
Expand All @@ -87,19 +86,7 @@ import { PhotoService } from '../services/photo.service';
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss'],
// CHANGE: Add the standalone component imports
imports: [
IonHeader,
IonToolbar,
IonTitle,
IonContent,
IonGrid,
IonRow,
IonCol,
IonImg,
IonFab,
IonFabButton,
IonIcon,
],
imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonGrid, IonRow, IonCol, IonFab, IonFabButton, IonIcon],
})
export class Tab2Page {
// CHANGE: Inject the PhotoService
Expand Down Expand Up @@ -242,7 +229,7 @@ export interface UserPhoto {
}
```

Next, switch to `tab2.page.html` to display the images. We'll add a [Grid component](../../api/grid.md) so the photos display neatly as they're added to the gallery. Inside the grid, loop through each photo in the `PhotoService`'s `photos` signal with the built-in [`@for`](https://angular.dev/guide/templates/control-flow#for-block-repeaters) block - calling `photoService.photos()` reads the signal's current value. For each item, add an [Image component](../../api/img.md) and set its `src` property to the photo's path.
Next, switch to `tab2.page.html` to display the images. We'll add a [Grid component](../../api/grid.md) so the photos display neatly as they're added to the gallery. Inside the grid, loop through each photo in the `PhotoService`'s `photos` signal with the built-in [`@for`](https://angular.dev/guide/templates/control-flow#for-block-repeaters) block - calling `photoService.photos()` reads the signal's current value. For each item, add an `<img>` element and set its `src` property to the photo's path.

```html
<ion-header [translucent]="true">
Expand All @@ -261,10 +248,10 @@ Next, switch to `tab2.page.html` to display the images. We'll add a [Grid compon
<!-- CHANGE: Add a grid component to display the photos. -->
<ion-grid>
<ion-row>
<!-- CHANGE: Create a new column and image component for each photo -->
@for (photo of photoService.photos(); track photo.webviewPath; let position = $index) {
<!-- CHANGE: Create a new column and image element for each photo -->
@for (photo of photoService.photos(); track photo.filepath; let position = $index) {
<ion-col size="6">
<ion-img [src]="photo.webviewPath"></ion-img>
<img [src]="photo.webviewPath" [attr.alt]="'Photo ' + (position + 1)" loading="lazy" />
</ion-col>
}
</ion-row>
Expand Down
15 changes: 1 addition & 14 deletions docs/angular/your-first-app/4-loading-photos.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@ import {
IonGrid,
IonRow,
IonCol,
IonImg,
IonFab,
IonFabButton,
IonIcon,
Expand All @@ -242,19 +241,7 @@ import { PhotoService } from '../services/photo.service';
selector: 'app-tab2',
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss'],
imports: [
IonHeader,
IonToolbar,
IonTitle,
IonContent,
IonGrid,
IonRow,
IonCol,
IonImg,
IonFab,
IonFabButton,
IonIcon,
],
imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonGrid, IonRow, IonCol, IonFab, IonFabButton, IonIcon],
})
export class Tab2Page implements OnInit {
public photoService = inject(PhotoService);
Expand Down
48 changes: 29 additions & 19 deletions docs/angular/your-first-app/7-live-reload.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ import {
IonGrid,
IonRow,
IonCol,
IonImg,
IonFab,
IonFabButton,
IonIcon,
Expand All @@ -109,19 +108,7 @@ import { PhotoService } from '../services/photo.service';
selector: 'app-tab2',
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss'],
imports: [
IonHeader,
IonToolbar,
IonTitle,
IonContent,
IonGrid,
IonRow,
IonCol,
IonImg,
IonFab,
IonFabButton,
IonIcon,
],
imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonGrid, IonRow, IonCol, IonFab, IonFabButton, IonIcon],
})
export class Tab2Page implements OnInit {
public photoService = inject(PhotoService);
Expand Down Expand Up @@ -169,7 +156,7 @@ export class Tab2Page implements OnInit {
}
```

Open `tab2.page.html` and add a new click handler to each `<ion-img>` element. When the app user taps on a photo in our gallery, well display an [Action Sheet](../../api/action-sheet.md) dialog with the option to either delete the selected photo or cancel (close) the dialog.
Open `tab2.page.html` and wrap each image in a `<button>` element with a click handler. When the app user taps on a photo in our gallery, we'll display an [Action Sheet](../../api/action-sheet.md) dialog with the option to either delete the selected photo or cancel (close) the dialog.

```html
<ion-header [translucent]="true">
Expand All @@ -187,10 +174,12 @@ Open `tab2.page.html` and add a new click handler to each `<ion-img>` element. W

<ion-grid>
<ion-row>
@for (photo of photoService.photos(); track photo.webviewPath; let position = $index) {
@for (photo of photoService.photos(); track photo.filepath; let position = $index) {
<ion-col size="6">
<!-- CHANGE: Add a click event listener to each image -->
<ion-img [src]="photo.webviewPath" (click)="showActionSheet(photo, position)"></ion-img>
<!-- CHANGE: Wrap the image in a button element and add a click event listener -->
<button (click)="showActionSheet(photo, position)">
<img [src]="photo.webviewPath" [attr.alt]="'Photo ' + (position + 1)" loading="lazy" />
</button>
</ion-col>
}
</ion-row>
Expand All @@ -204,10 +193,31 @@ Open `tab2.page.html` and add a new click handler to each `<ion-img>` element. W
</ion-content>
```

Add the following CSS to `tab2.page.scss` to style the gallery buttons and images:

```css
ion-col > button {
display: block;
width: 100%;
background: none;
border: none;
padding: 0;
margin: 0;
cursor: pointer;
font: inherit;
}

button img {
display: block;
width: 100%;
height: auto;
}
```

Tap on a photo again and choose the “Delete” option. The photo is deleted! Implemented much faster using Live Reload. 💪

:::note
Remember, you can find the complete source code for this app [here](https://github.com/ionic-team/photo-gallery-capacitor-ng).
Remember, you can find the complete source code for this app [here](https://github.com/ionic-team/tutorial-photo-gallery-angular).
:::

In the final portion of this tutorial, we’ll walk you through the basics of the Appflow product used to build and deploy your application to users' devices.
11 changes: 5 additions & 6 deletions docs/react/your-first-app/2-taking-photos.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export interface UserPhoto {
}
```

Next, switch to `Tab2.tsx` to display the images. We'll add a [Grid component](../../api/grid.md) to ensure the photos display neatly as they're added to the gallery. Inside the grid, loop through each photo in the `UserPhoto`'s `photos` array. For each item, add an [Image component](../../api/img.md) and set its `src` property to the photo's path.
Next, switch to `Tab2.tsx` to display the images. We'll add a [Grid component](../../api/grid.md) to ensure the photos display neatly as they're added to the gallery. Inside the grid, loop through each photo in the `UserPhoto`'s `photos` array. For each item, add an `<img>` element and set its `src` property to the photo's path.

```tsx
import { camera } from 'ionicons/icons';
Expand All @@ -218,7 +218,6 @@ import {
IonGrid,
IonRow,
IonCol,
IonImg,
} from '@ionic/react';
import { usePhotoGallery } from '../hooks/usePhotoGallery';

Expand All @@ -243,10 +242,10 @@ const Tab2: React.FC = () => {
{/* CHANGE: Add a grid component to display the photos */}
<IonGrid>
<IonRow>
{/* CHANGE: Create a new column and image component for each photo */}
{photos.map((photo) => (
<IonCol size="6" key={photo.filepath}>
<IonImg src={photo.webviewPath} />
{/* CHANGE: Create a new column and image element for each photo */}
{photos.map((photo, index) => (
<IonCol size="6" key={index}>
<img src={photo.webviewPath} alt={`Photo ${index + 1}`} loading="lazy" />
</IonCol>
))}
</IonRow>
Expand Down
40 changes: 31 additions & 9 deletions docs/react/your-first-app/7-live-reload.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ import {
IonGrid,
IonRow,
IonCol,
IonImg,
IonActionSheet,
} from '@ionic/react';
// CHANGE: Add import
Expand Down Expand Up @@ -131,9 +130,9 @@ const Tab2: React.FC = () => {

<IonGrid>
<IonRow>
{photos.map((photo) => (
<IonCol size="6" key={photo.filepath}>
<IonImg src={photo.webviewPath} />
{photos.map((photo, index) => (
<IonCol size="6" key={index}>
<img src={photo.webviewPath} alt={`Photo ${index + 1}`} loading="lazy" />
</IonCol>
))}
</IonRow>
Expand Down Expand Up @@ -179,21 +178,44 @@ const Tab2: React.FC = () => {
export default Tab2;
```

Add a click handler to the `<IonImg>` element. When the app user taps on a photo in our gallery, well display an [Action Sheet](../../api/action-sheet.md) dialog with the option to either delete the selected photo or cancel (close) the dialog.
Wrap each image in a `<button>` element with a click handler. When the app user taps on a photo in our gallery, we'll display an [Action Sheet](../../api/action-sheet.md) dialog with the option to either delete the selected photo or cancel (close) the dialog.

```tsx
<IonGrid>
<IonRow>
{photos.map((photo) => (
<IonCol size="6" key={photo.filepath}>
{/* CHANGE: Add a click event listener to each image. */}
<IonImg src={photo.webviewPath} onClick={() => setPhotoToDelete(photo)} />
{photos.map((photo, index) => (
<IonCol size="6" key={index}>
{/* CHANGE: Wrap the image in a button element and add a click event listener. */}
<button onClick={() => setPhotoToDelete(photo)}>
<img src={photo.webviewPath} alt={`Photo ${index + 1}`} loading="lazy" />
</button>
</IonCol>
))}
</IonRow>
</IonGrid>
```

Add the following CSS to `Tab2.css` to style the gallery buttons and images:

```css
ion-col button {
display: block;
width: 100%;
background: none;
border: none;
padding: 0;
margin: 0;
cursor: pointer;
font: inherit;
}

button img {
display: block;
width: 100%;
height: auto;
}
```

Remember that removing the photo from the `photos` array triggers the `setPhotos` method for us automatically.

Tap on a photo again and choose the “Delete” option. The photo is deleted! Implemented much faster using Live Reload. 💪
Expand Down
9 changes: 4 additions & 5 deletions docs/vue/your-first-app/2-taking-photos.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ export interface UserPhoto {
}
```

Next, switch to `Tab2Page.vue` to display the images. We'll add a [Grid component](../../api/grid.md) to ensure the photos display neatly as they're added to the gallery. Inside the grid, loop through each photo in the `UserPhoto`'s `photos` array. For each item, add an [Image component](../../api/img.md) and set its `src` property to the photo's path.
Next, switch to `Tab2Page.vue` to display the images. We'll add a [Grid component](../../api/grid.md) to ensure the photos display neatly as they're added to the gallery. Inside the grid, loop through each photo in the `UserPhoto`'s `photos` array. For each item, add an `<img>` element and set its `src` property to the photo's path.

```vue
<template>
Expand All @@ -212,9 +212,9 @@ Next, switch to `Tab2Page.vue` to display the images. We'll add a [Grid componen
<!-- CHANGE: Add a grid component to display the photos -->
<ion-grid>
<ion-row>
<!-- CHANGE: Create a new column and image component for each photo -->
<ion-col size="6" :key="photo.filepath" v-for="photo in photos">
<ion-img :src="photo.webviewPath"></ion-img>
<!-- CHANGE: Create a new column and image element for each photo -->
<ion-col size="6" :key="photo.filepath" v-for="(photo, index) in photos">
<img :src="photo.webviewPath" :alt="`Photo ${index + 1}`" loading="lazy" />
</ion-col>
</ion-row>
</ion-grid>
Expand Down Expand Up @@ -243,7 +243,6 @@ import {
IonGrid,
IonRow,
IonCol,
IonImg,
} from '@ionic/vue';

import { usePhotoGallery } from '@/composables/usePhotoGallery';
Expand Down
29 changes: 25 additions & 4 deletions docs/vue/your-first-app/7-live-reload.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const showActionSheet = async (photo: UserPhoto) => {
</script>
```

Add a click handler to the `<ion-img>` element. When the app user taps on a photo in our gallery, well display an [Action Sheet](../../api/action-sheet.md) dialog with the option to either delete the selected photo or cancel (close) the dialog.
Wrap each image in a `<button>` element with a click handler. When the app user taps on a photo in our gallery, we'll display an [Action Sheet](../../api/action-sheet.md) dialog with the option to either delete the selected photo or cancel (close) the dialog.

```vue
<template>
Expand All @@ -154,9 +154,11 @@ Add a click handler to the `<ion-img>` element. When the app user taps on a phot

<ion-grid>
<ion-row>
<ion-col size="6" :key="photo.filepath" v-for="photo in photos">
<!-- CHANGE: Add a click event listener to each image -->
<ion-img :src="photo.webviewPath" @click="showActionSheet(photo)"></ion-img>
<ion-col size="6" v-for="(photo, index) in photos" :key="photo">
<!-- CHANGE: Wrap the image in a button element and add a click event listener -->
<button @click="showActionSheet(photo)">
<img :src="photo.webviewPath" :alt="`Photo ${index + 1}`" loading="lazy" />
</button>
</ion-col>
</ion-row>
</ion-grid>
Expand All @@ -169,6 +171,25 @@ Add a click handler to the `<ion-img>` element. When the app user taps on a phot
</ion-content>
</ion-page>
</template>

<style scoped>
ion-col > button {
display: block;
width: 100%;
background: none;
border: none;
padding: 0;
margin: 0;
cursor: pointer;
font: inherit;
}

button img {
display: block;
width: 100%;
height: auto;
}
</style>
```

Remember that removing the photo from the `photos` array triggers the `cachePhotos` method for us automatically.
Expand Down
Loading