Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular (and some Vue) edits and code examples for Data #8166

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e08f3df
remove reference of renameModelFields
chrisbonifacio Jul 19, 2024
88f45e8
Merge branch 'main' of github.com:aws-amplify/docs
chrisbonifacio Aug 21, 2024
e8acc67
add code examples for angular
chrisbonifacio Dec 16, 2024
b03c5c8
Merge branch 'main' of github.com:aws-amplify/docs into angular-data-…
chrisbonifacio Dec 16, 2024
e7259e6
add angular specific code examples
chrisbonifacio Dec 16, 2024
8122836
add angular and vue examples
chrisbonifacio Dec 16, 2024
742c2a0
update vue example
chrisbonifacio Dec 16, 2024
5144ff3
add angular example for polly
chrisbonifacio Dec 16, 2024
392d84e
add angular example for bedrock
chrisbonifacio Dec 16, 2024
9590dc1
add angular example for rekognition
chrisbonifacio Dec 16, 2024
13832e1
remove complete example from angular and vue pages
chrisbonifacio Dec 16, 2024
fd37502
Update src/pages/[platform]/build-a-backend/data/custom-business-logi…
chrisbonifacio Dec 17, 2024
72e0e8c
Update src/pages/[platform]/build-a-backend/data/custom-business-logi…
chrisbonifacio Dec 17, 2024
3fa3f03
Update src/pages/[platform]/build-a-backend/data/custom-business-logi…
chrisbonifacio Dec 17, 2024
e3ad85f
Update src/pages/[platform]/build-a-backend/data/query-data/index.mdx
chrisbonifacio Dec 17, 2024
08e9356
make import in snippet consistent with other angular code snippets
chrisbonifacio Dec 17, 2024
752615c
Update src/pages/[platform]/build-a-backend/data/query-data/index.mdx
chrisbonifacio Dec 17, 2024
9c64e98
Update src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx
chrisbonifacio Dec 17, 2024
75ed92f
Update src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx
chrisbonifacio Dec 17, 2024
d9defaf
Update src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx
chrisbonifacio Dec 17, 2024
c4b495d
Update src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx
chrisbonifacio Dec 18, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ When deploying your app to production, you need to [add the database connection

## Rename generated models and fields

To improve the ergonomics of your API, you might want to rename the generate fields or types to better accommodate your use case. Use the `renameModels()` and `renameModelFields()` modifiers to rename the auto-inferred data models and their fields.
To improve the ergonomics of your API, you might want to rename the generate fields or types to better accommodate your use case. Use the `renameModels()` modifier to rename the auto-inferred data models.

```ts
// Rename models or fields to be more idiomatic for frontend code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ Amplify.configure(outputs);

Example frontend code to create an audio buffer for playback using a text input.

<InlineFilter filters={["react", "javascript", "nextjs", "react-native"]}>
```ts title="App.tsx"
import "./App.css";
import { generateClient } from "aws-amplify/api";
Expand Down Expand Up @@ -267,4 +268,53 @@ function App() {

export default App;
```
</InlineFilter>

<InlineFilter filters={["angular"]}>
```ts title="app.component.ts"
import type { Schema } from '../../../amplify/data/resource';
import { Component } from '@angular/core';
import { generateClient } from 'aws-amplify/api';
import { getUrl } from 'aws-amplify/storage';

const client = generateClient<Schema>();

type PollyReturnType = Schema['convertTextToSpeech']['returnType'];

@Component({
selector: 'app-root',
template: `
<div class="flex flex-col">
<button (click)="synthesize()">Synth</button>
<button (click)="fetchAudio()">Fetch audio</button>
<a [href]="src">Get audio file</a>
</div>
`,
styleUrls: ['./app.component.css'],
})
export class App {
src: string = '';
file: PollyReturnType = '';

async synthesize() {
const { data, errors } = await client.mutations.convertTextToSpeech({
text: 'Hello World!',
});

if (!errors && data) {
this.file = data;
} else {
console.log(errors);
}
}

async fetchAudio() {
const res = await getUrl({
path: 'public/' + this.file,
});

this.src = res.url.toString();
}
}
```
</InlineFilter>
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ Amplify.configure(outputs);

This code sets up a React app to upload an image to an S3 bucket and then use Amazon Rekognition to recognize the text in the uploaded image.

<InlineFilter filters={["react", "javascript", "nextjs", "react-native"]}>
```ts title="App.tsx"
import { type ChangeEvent, useState } from "react";
import { generateClient } from "aws-amplify/api";
Expand Down Expand Up @@ -282,3 +283,71 @@ function App() {

export default App;
```
</InlineFilter>
<InlineFilter filters={["angular"]}>
```ts title="app.component.ts"
import type { Schema } from '../../../amplify/data/resource';
import { Component } from '@angular/core';
import { generateClient } from 'aws-amplify/api';
import { uploadData } from 'aws-amplify/storage';
import { CommonModule } from '@angular/common';

// Generating the client
const client = generateClient<Schema>();

type IdentifyTextReturnType = Schema['identifyText']['returnType'];

@Component({
selector: 'app-text-recognition',
standalone: true,
imports: [CommonModule],
template: `
<div>
<h1>Amazon Rekognition Text Recognition</h1>
<div>
<input type="file" (change)="handleTranslate($event)" />
<button (click)="recognizeText()">Recognize Text</button>
<div>
<h3>Recognized Text:</h3>
{{ textData }}
</div>
</div>
</div>
`,
})
export class TodosComponent {
// Component properties instead of React state
path: string = '';
textData?: IdentifyTextReturnType;

// Function to handle file upload to S3 bucket
async handleTranslate(event: Event) {
const target = event.target as HTMLInputElement;
if (target.files && target.files.length > 0) {
const file = target.files[0];
const s3Path = 'public/' + file.name;

try {
await uploadData({
path: s3Path,
data: file,
});

this.path = s3Path;
} catch (error) {
console.error(error);
}
}
}

// Function to recognize text from the uploaded image
async recognizeText() {
// Identifying text in the uploaded image
const { data } = await client.queries.identifyText({
path: this.path, // File name
});
this.textData = data;
}
}
```
</InlineFilter>
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ const { data, errors } = await client.queries.generateHaiku({

Here's an example of a simple UI that prompts a generative AI model to create a haiku based on user input:

<InlineFilter filters={["react", "javascript", "nextjs", "react-native", "vue"]}>
```tsx title="App.tsx"
import type { Schema } from '@/amplify/data/resource';
import type { FormEvent } from 'react';
Expand Down Expand Up @@ -402,6 +403,65 @@ export default function App() {
);
}
```
</InlineFilter>

<InlineFilter filters={['angular']}>
```ts title="app.component.ts"
import type { Schema } from '../../../amplify/data/resource';
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Amplify } from 'aws-amplify';
import { generateClient } from 'aws-amplify/api';
import outputs from '../../../amplify_outputs.json';

Amplify.configure(outputs);

const client = generateClient<Schema>();

@Component({
selector: 'app-haiku',
standalone: true,
imports: [FormsModule],
template: `
<main
class="flex min-h-screen flex-col items-center justify-center p-24 dark:text-white"
>
<div>
<h1 class="text-3xl font-bold text-center mb-4">Haiku Generator</h1>
<form class="mb-4 self-center max-w-[500px]" (ngSubmit)="sendPrompt()">
<input
class="text-black p-2 w-full"
placeholder="Enter a prompt..."
name="prompt"
[(ngModel)]="prompt"
/>
</form>
<div class="text-center">
<pre>{{ answer }}</pre>
</div>
</div>
</main>
`,
})
export class HaikuComponent {
prompt: string = '';
answer: string | null = null;

async sendPrompt() {
const { data, errors } = await client.queries.generateHaiku({
prompt: this.prompt,
});

if (!errors) {
this.answer = data;
this.prompt = '';
} else {
console.log(errors);
}
}
}
```
</InlineFilter>

![A webpage titled "Haiku Generator" and input field. "Frank Herbert's Dune" is entered and submitted. Shortly after, a haiku is rendered to the page.](/images/haiku-generator.gif)

Expand Down
103 changes: 102 additions & 1 deletion src/pages/[platform]/build-a-backend/data/query-data/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ const {
});
```

<InlineFilter filters={["react", "javascript", "nextjs", "react-native"]}>

If you're building a React application, you can use the `usePagination` hook in Amplify UI to help with managing the pagination user experience.

```js
Expand Down Expand Up @@ -187,6 +189,8 @@ export const PaginationHasMorePagesExample = () => {
};
```

</InlineFilter>

<Callout>

**Limitations:**
Expand Down Expand Up @@ -214,7 +218,11 @@ const { data: blogWithSubsetOfData, errors } = await client.models.Blog.get(

## TypeScript type helpers for Amplify Data

When using TypeScript, you frequently need to specify data model types for type generics. For instance, with React's `useState`, you provide a type in TypeScript to ensure type-safety in your component code using the state. Use the `Schema["MODEL_NAME"]["type"]` pattern to get TypeScript types for the shapes of data models returned from the backend API. This allows you to get consumable TypeScript types for the shapes of the data model return values coming from the backend API.
When using TypeScript, you frequently need to specify data model types for type generics.

<InlineFilter filters={["react", "javascript", "nextjs", "react-native"]}>

For instance, with React's `useState`, you provide a type in TypeScript to ensure type-safety in your component code using the state. Use the `Schema["MODEL_NAME"]["type"]` pattern to get TypeScript types for the shapes of data models returned from the backend API.

```ts
import { type Schema } from '@/amplify/data/resource';
Expand All @@ -224,8 +232,21 @@ type Post = Schema['Post']['type'];
const [posts, setPosts] = useState<Post[]>([]);
```

</InlineFilter>

<InlineFilter filters={["angular", "vue"]}>

```ts
import { type Schema } from '../../../amplify/data/resource';

type Post = Schema['Post']['type'];
```

</InlineFilter>

You can combine the `Schema["MODEL_NAME"]["type"]` type with the `SelectionSet` helper type to describe the return type of API requests using the `selectionSet` parameter:

<InlineFilter filters={["react", "javascript", "nextjs", "react-native"]}>
```ts
import type { SelectionSet } from 'aws-amplify/data';
import type { Schema } from '../amplify/data/resource';
Expand All @@ -245,6 +266,86 @@ const fetchPosts = async () => {
}
```

</InlineFilter>

<InlineFilter filters={['vue']}>
```ts
<script setup lang="ts">
import type { Schema } from '../../../amplify/data/resource';
import { ref, onMounted } from 'vue';
import { generateClient, type SelectionSet } from 'aws-amplify/data';

const client = generateClient<Schema>();

const selectionSet = ['content', 'blog.author.*', 'comments.*'] as const;
chrisbonifacio marked this conversation as resolved.
Show resolved Hide resolved

type PostWithComments = SelectionSet<
Schema['Post']['type'],
typeof selectionSet
>;

const posts = ref<PostWithComments[]>([]);

const fetchPosts = async (): Promise<void> => {
const { data: postsWithComments } = await client.models.Post.list({
selectionSet,
});
posts.value = postsWithComments;
};

onMounted(() => {
fetchPosts();
});
</script>

<template v-for="post in posts" :key="post.id">
<li>{{ post.content }}</li>
</template>
```
</InlineFilter>

<InlineFilter filters={["angular"]}>
```ts
import type { Schema } from '../../../amplify/data/resource';
import { Component, OnInit } from '@angular/core';
import { generateClient, type SelectionSet } from 'aws-amplify/data';
import { CommonModule } from '@angular/common';

const client = generateClient<Schema>();

const selectionSet = ['content', 'blog.author.*', 'comments.*'] as const;

type PostWithComments = SelectionSet<
Schema['Post']['type'],
typeof selectionSet
>;

@Component({
selector: 'app-todos',
standalone: true,
imports: [CommonModule],
templateUrl: './todos.component.html',
styleUrls: ['./todos.component.css'],
})
export class TodosComponent implements OnInit {
posts: PostWithComments[] = [];

constructor() {}

ngOnInit(): void {
this.fetchPosts();
}

async fetchPosts(): Promise<void> {
const { data: postsWithComments } = await client.models.Post.list({
selectionSet,
});
this.posts = postsWithComments;
}
}
```
</InlineFilter>

## Cancel read requests

You can cancel any query API request by calling `.cancel` on the query request promise that's returned by `.list(...)` or `.get(...)`.
Expand Down
Loading
Loading