;` field after the `selectedBook`.
+* Added `this.authors$ = bookService.getAuthorLookup().pipe(map((r) => r.items));` into the constructor.
+* Added ` authorId: [this.selectedBook.authorId || null, Validators.required],` into the `buildForm()` function.
+
+Open the `/src/app/book/book.component.html` and add the following form group just before the book name form group:
+
+````html
+
+ *
+
+
+````
+
+That's all. Just run the application and try to create or edit an author.
{{end}}
\ No newline at end of file
diff --git a/docs/en/Tutorials/Part-2.md b/docs/en/Tutorials/Part-2.md
index c947f4495d..bcec504886 100644
--- a/docs/en/Tutorials/Part-2.md
+++ b/docs/en/Tutorials/Part-2.md
@@ -347,9 +347,9 @@ This is a fully working, server side paged, sorted and localized table of books.
## Install NPM packages
-> Notice: This tutorial is based on the ABP Framework v3.0.3+ If your project version is older, then please upgrade your solution. See the [migration guide](../UI/Angular/Migration-Guide-v3.md) if you are upgrading an existing project with v2.x.
+> Notice: This tutorial is based on the ABP Framework v3.1.0+ If your project version is older, then please upgrade your solution. See the [migration guide](../UI/Angular/Migration-Guide-v3.md) if you are upgrading an existing project with v2.x.
-If you haven't done it before, open a new command line interface (terminal window) and go to your `angular` folder and then run `yarn` command to install NPM packages:
+If you haven't done it before, open a new command line interface (terminal window) and go to your `angular` folder and then run `yarn` command to install the NPM packages:
```bash
yarn
@@ -473,9 +473,9 @@ Run the following command in the `angular` folder:
abp generate-proxy
```
-The generated files looks like below:
+This command will create the following files under the `/src/app/proxy/books` folder:
-
+
### BookComponent
@@ -484,8 +484,7 @@ Open the `/src/app/book/book.component.ts` file and replace the content as below
```js
import { ListService, PagedResultDto } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
-import { BookDto } from './models';
-import { BookService } from './services';
+import { BookService, BookDto } from '@proxy/books';
@Component({
selector: 'app-book',
@@ -499,7 +498,7 @@ export class BookComponent implements OnInit {
constructor(public readonly list: ListService, private bookService: BookService) {}
ngOnInit() {
- const bookStreamCreator = (query) => this.bookService.getListByInput(query);
+ const bookStreamCreator = (query) => this.bookService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
this.book = response;
diff --git a/docs/en/Tutorials/Part-3.md b/docs/en/Tutorials/Part-3.md
index 13aa5df8c3..be3dd75d64 100644
--- a/docs/en/Tutorials/Part-3.md
+++ b/docs/en/Tutorials/Part-3.md
@@ -656,8 +656,7 @@ Open `/src/app/book/book.component.ts` and replace the content as below:
```js
import { ListService, PagedResultDto } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
-import { BookDto } from './models';
-import { BookService } from './services';
+import { BookService, BookDto } from '@proxy/books';
@Component({
selector: 'app-book',
@@ -673,7 +672,7 @@ export class BookComponent implements OnInit {
constructor(public readonly list: ListService, private bookService: BookService) {}
ngOnInit() {
- const bookStreamCreator = (query) => this.bookService.getListByInput(query);
+ const bookStreamCreator = (query) => this.bookService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
this.book = response;
@@ -749,8 +748,8 @@ Open `/src/app/book/book.component.ts` and replace the content as below:
```js
import { ListService, PagedResultDto } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
-import { BookDto, BookType } from './models'; // add BookType
-import { BookService } from './services';
+// import bookTypeOptions from @proxy/books
+import { BookService, BookDto, bookTypeOptions } from '@proxy/books';
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; // add this
@Component({
@@ -764,12 +763,8 @@ export class BookComponent implements OnInit {
form: FormGroup; // add this line
- bookType = BookType; // add this line
-
// add bookTypes as a list of BookType enum members
- bookTypes = Object.keys(this.bookType).filter(
- (key) => typeof this.bookType[key] === 'number'
- );
+ bookTypes = bookTypeOptions;
isModalOpen = false;
@@ -780,7 +775,7 @@ export class BookComponent implements OnInit {
) {}
ngOnInit() {
- const bookStreamCreator = (query) => this.bookService.getListByInput(query);
+ const bookStreamCreator = (query) => this.bookService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
this.book = response;
@@ -808,7 +803,7 @@ export class BookComponent implements OnInit {
return;
}
- this.bookService.createByInput(this.form.value).subscribe(() => {
+ this.bookService.create(this.form.value).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
@@ -819,7 +814,6 @@ export class BookComponent implements OnInit {
* Imported `FormGroup`, `FormBuilder` and `Validators` from `@angular/forms`.
* Added `form: FormGroup` property.
-* Added `bookType` property so that you can reach `BookType` enum members from template.
* Added `bookTypes` property as a list of `BookType` enum members. That will be used in form options.
* Injected `FormBuilder` into the constructor. [FormBuilder](https://angular.io/api/forms/FormBuilder) provides convenient methods for generating form controls. It reduces the amount of boilerplate needed to build complex forms.
* Added `buildForm` method to the end of the file and executed the `buildForm()` in the `createBook` method.
@@ -844,7 +838,7 @@ Open `/src/app/book/book.component.html` and replace ` Type *
@@ -910,8 +904,7 @@ Open `/src/app/book/book.component.ts` and replace the content as below:
```js
import { ListService, PagedResultDto } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
-import { BookDto, BookType } from './models';
-import { BookService } from './services';
+import { BookService, BookDto, bookTypeOptions } from '@proxy/books';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
// added this line
@@ -931,11 +924,7 @@ export class BookComponent implements OnInit {
form: FormGroup;
- bookType = BookType;
-
- bookTypes = Object.keys(this.bookType).filter(
- (key) => typeof this.bookType[key] === 'number'
- );
+ bookTypes = bookTypeOptions;
isModalOpen = false;
@@ -946,7 +935,7 @@ export class BookComponent implements OnInit {
) {}
ngOnInit() {
- const bookStreamCreator = (query) => this.bookService.getListByInput(query);
+ const bookStreamCreator = (query) => this.bookService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
this.book = response;
@@ -972,7 +961,7 @@ export class BookComponent implements OnInit {
return;
}
- this.bookService.createByInput(this.form.value).subscribe(() => {
+ this.bookService.create(this.form.value).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
@@ -995,8 +984,7 @@ Open `/src/app/book/book.component.ts` and replace the content as shown below:
```js
import { ListService, PagedResultDto } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
-import { BookDto, BookType, CreateUpdateBookDto } from './models';
-import { BookService } from './services';
+import { BookService, BookDto, bookTypeOptions } from '@proxy/books';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
@@ -1009,15 +997,11 @@ import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap
export class BookComponent implements OnInit {
book = { items: [], totalCount: 0 } as PagedResultDto;
- selectedBook = new BookDto(); // declare selectedBook
+ selectedBook = {} as BookDto; // declare selectedBook
form: FormGroup;
- bookType = BookType;
-
- bookTypes = Object.keys(this.bookType).filter(
- (key) => typeof this.bookType[key] === 'number'
- );
+ bookTypes = bookTypeOptions;
isModalOpen = false;
@@ -1028,7 +1012,7 @@ export class BookComponent implements OnInit {
) {}
ngOnInit() {
- const bookStreamCreator = (query) => this.bookService.getListByInput(query);
+ const bookStreamCreator = (query) => this.bookService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
this.book = response;
@@ -1036,14 +1020,14 @@ export class BookComponent implements OnInit {
}
createBook() {
- this.selectedBook = new BookDto(); // reset the selected book
+ this.selectedBook = {} as BookDto; // reset the selected book
this.buildForm();
this.isModalOpen = true;
}
// Add editBook method
editBook(id: string) {
- this.bookService.getById(id).subscribe((book) => {
+ this.bookService.get(id).subscribe((book) => {
this.selectedBook = book;
this.buildForm();
this.isModalOpen = true;
@@ -1069,8 +1053,8 @@ export class BookComponent implements OnInit {
}
const request = this.selectedBook.id
- ? this.bookService.updateByIdAndInput(this.form.value, this.selectedBook.id)
- : this.bookService.createByInput(this.form.value);
+ ? this.bookService.update(this.selectedBook.id, this.form.value)
+ : this.bookService.create(this.form.value);
request.subscribe(() => {
this.isModalOpen = false;
@@ -1155,7 +1139,7 @@ constructor(
delete(id: string) {
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => {
if (status === Confirmation.Status.confirm) {
- this.bookService.deleteById(id).subscribe(() => this.list.get());
+ this.bookService.delete(id).subscribe(() => this.list.get());
}
});
}
diff --git a/docs/en/Tutorials/Part-9.md b/docs/en/Tutorials/Part-9.md
index 1b9451700d..0d78d584b8 100644
--- a/docs/en/Tutorials/Part-9.md
+++ b/docs/en/Tutorials/Part-9.md
@@ -621,7 +621,7 @@ abp generate-proxy
This command generates the service proxy for the author service and the related model (DTO) classes:
-
+
### AuthorComponent
@@ -630,8 +630,7 @@ Open the `/src/app/author/author.component.ts` file and replace the content as b
```js
import { Component, OnInit } from '@angular/core';
import { ListService, PagedResultDto } from '@abp/ng.core';
-import { AuthorDto } from './models';
-import { AuthorService } from './services';
+import { AuthorService, AuthorDto } from '@proxy/authors';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared';
@@ -649,7 +648,7 @@ export class AuthorComponent implements OnInit {
form: FormGroup;
- selectedAuthor = new AuthorDto();
+ selectedAuthor = {} as AuthorDto;
constructor(
public readonly list: ListService,
@@ -659,7 +658,7 @@ export class AuthorComponent implements OnInit {
) {}
ngOnInit(): void {
- const authorStreamCreator = (query) => this.authorService.getListByInput(query);
+ const authorStreamCreator = (query) => this.authorService.getList(query);
this.list.hookToQuery(authorStreamCreator).subscribe((response) => {
this.author = response;
@@ -667,13 +666,13 @@ export class AuthorComponent implements OnInit {
}
createAuthor() {
- this.selectedAuthor = new AuthorDto();
+ this.selectedAuthor = {} as AuthorDto;
this.buildForm();
this.isModalOpen = true;
}
editAuthor(id: string) {
- this.authorService.getById(id).subscribe((author) => {
+ this.authorService.get(id).subscribe((author) => {
this.selectedAuthor = author;
this.buildForm();
this.isModalOpen = true;
@@ -697,14 +696,14 @@ export class AuthorComponent implements OnInit {
if (this.selectedAuthor.id) {
this.authorService
- .updateByIdAndInput(this.form.value, this.selectedAuthor.id)
+ .update(this.selectedAuthor.id, this.form.value)
.subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
});
} else {
- this.authorService.createByInput(this.form.value).subscribe(() => {
+ this.authorService.create(this.form.value).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
@@ -716,7 +715,7 @@ export class AuthorComponent implements OnInit {
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure')
.subscribe((status) => {
if (status === Confirmation.Status.confirm) {
- this.authorService.deleteById(id).subscribe(() => this.list.get());
+ this.authorService.delete(id).subscribe(() => this.list.get());
}
});
}
diff --git a/docs/en/Tutorials/images/bookstore-angular-author-selection.png b/docs/en/Tutorials/images/bookstore-angular-author-selection.png
new file mode 100644
index 0000000000..bb604233ab
Binary files /dev/null and b/docs/en/Tutorials/images/bookstore-angular-author-selection.png differ
diff --git a/docs/en/Tutorials/images/bookstore-angular-service-proxy-author-2.png b/docs/en/Tutorials/images/bookstore-angular-service-proxy-author-2.png
new file mode 100644
index 0000000000..d76179bb78
Binary files /dev/null and b/docs/en/Tutorials/images/bookstore-angular-service-proxy-author-2.png differ
diff --git a/docs/en/Tutorials/images/bookstore-books-with-authorname-angular.png b/docs/en/Tutorials/images/bookstore-books-with-authorname-angular.png
new file mode 100644
index 0000000000..6f081c16f9
Binary files /dev/null and b/docs/en/Tutorials/images/bookstore-books-with-authorname-angular.png differ
diff --git a/docs/en/Tutorials/images/generated-proxies-3.png b/docs/en/Tutorials/images/generated-proxies-3.png
new file mode 100644
index 0000000000..2a94f4e389
Binary files /dev/null and b/docs/en/Tutorials/images/generated-proxies-3.png differ