From 88bf958dec027c8b311846c067a7ad6d8f7c87f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 6 Apr 2021 17:32:56 +0300 Subject: [PATCH] Completed initial version of the TODO app tutorial. --- docs/en/Tutorials/Todo/Index.md | 362 +++++++++++++++++++++++++++ docs/en/Tutorials/Todo/todo-api.png | Bin 0 -> 11114 bytes docs/en/Tutorials/Todo/todo-list.png | Bin 0 -> 12311 bytes 3 files changed, 362 insertions(+) create mode 100644 docs/en/Tutorials/Todo/Index.md create mode 100644 docs/en/Tutorials/Todo/todo-api.png create mode 100644 docs/en/Tutorials/Todo/todo-list.png diff --git a/docs/en/Tutorials/Todo/Index.md b/docs/en/Tutorials/Todo/Index.md new file mode 100644 index 0000000000..d026649451 --- /dev/null +++ b/docs/en/Tutorials/Todo/Index.md @@ -0,0 +1,362 @@ +# Quick Tutorial + +````json +//[doc-params] +{ + "UI": ["MVC", "Blazor", "BlazorServer", "NG"], + "DB": ["EF", "Mongo"], +} +```` + +This is a single-part, quick tutorial to build a simple TODO application with the ABP Framework. Here, a sample screenshot from the final application: + +![todo-list](todo-list.png) + +### Source Code + +You can find source code of the example application [here](https://github.com/abpframework/abp-samples/tree/master/TodoApp). + +## Creating a New Solution + +Please create a new solution, named `TodoApp`, by following the [Getting Started](../../Getting-Started.md) document. + +**TODO: Instead, we can create the solution here!** + +## Domain Layer + +This application has a single [entity](../../Entities.md) and we are starting by creating it. Create a new `TodoItem` class inside the *TodoApp.Domain* project: + +````csharp +using System; +using Volo.Abp.Domain.Entities; + +namespace TodoApp +{ + public class TodoItem : BasicAggregateRoot + { + public string Text { get; set; } + } +} +```` + +`BasicAggregateRoot` is one the simplest base class to create root entities, and `Guid` is the primary key (`Id`) of the entity here. + +## Database Integration + +Next step is to setup the [Entity Framework Core](../../Entity-Framework-Core.md) configuration. Open the `TodoAppDbContext` class in the `EntityFrameworkCore` folder of the *TodoApp.EntityFrameworkCore* project and add a new `DbSet` property to this class: + +````csharp +public DbSet TodoItems { get; set; } +```` + +Then open the `TodoAppDbContextModelCreatingExtensions` class in the same folder and add a mapping configuration for the `TodoItem` class as shown below: + +````csharp +public static void ConfigureTodoApp(this ModelBuilder builder) +{ + Check.NotNull(builder, nameof(builder)); + + builder.Entity(b => + { + b.ToTable("TodoItems"); + }); +} +```` + +We've mapped `TodoItem` entity to a `TodoItems` table in the database. + +**TODO: DB MIGRATIONS** + +Now, we can use ABP repositories to save and retrieve todo items, as we'll do in the next section. + +## Application Layer + +An [Application Service](../../Application-Services.md) is used to perform use cases of the application. We need to perform the following use cases; + +* Get the list of todo items +* Create a new todo item +* Delete an existing todo item + +We can start by defining an interface for the application service. Create a new `ITodoAppService` interface in the *TodoApp.Application.Contracts* project, as shown below: + +````csharp +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace TodoApp +{ + public interface ITodoAppService : IApplicationService + { + Task> GetListAsync(); + Task CreateAsync(string text); + Task DeleteAsync(Guid id); + } +} +```` + +`GetListAsync` and `CreateAsync` methods return `TodoItemDto`. Applications Services typically gets and returns DTOs ([Data Transfer Objects](../../Data-Transfer-Objects.md)) instead of entities. So, we should define the DTO class here. Create a new `TodoItemDto` class inside the *TodoApp.Application.Contracts* project: + +````csharp +using System; + +namespace TodoApp +{ + public class TodoItemDto + { + public Guid Id { get; set; } + public string Text { get; set; } + } +} +```` + +This is a very simple DTO class that matches to our `TodoItem` entity. We are ready to implement the `ITodoAppService`. Create a `TodoAppService` class inside the *TodoApp.Application* project, as shown below: + +````csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.Domain.Repositories; + +namespace TodoApp +{ + public class TodoAppService : ApplicationService, ITodoAppService + { + private readonly IRepository _todoItemRepository; + + public TodoAppService(IRepository todoItemRepository) + { + _todoItemRepository = todoItemRepository; + } + + // TODO: Implement the methods + } +} +```` + +This class inherits from the `ApplicationService` class of the ABP Framework and implements the `ITodoAppService` that was defined before. ABP provides default generic [repositories](../../Repositories.md) for the entities. We can use them to perform the fundamental database operations. This class [injects](../../Dependency-Injection.md) `IRepository`, which is the default repository for the `TodoItem` entity. We will use it to implement the use cases described before. + +Let's start by implementing the `GetListAsync` method: + +````csharp +public async Task> GetListAsync() +{ + var items = await _todoItemRepository.GetListAsync(); + return items + .Select(item => new TodoItemDto + { + Id = item.Id, + Text = item.Text + }).ToList(); +} +```` + +We are simply getting the complete `TodoItem` list from database, mapping them to `TodoItemDto` objects and returning as the result. + +Next method is `CreateAsync` and we can implement it as shown below: + +````csharp +public async Task CreateAsync(string text) +{ + var todoItem = await _todoItemRepository.InsertAsync( + new TodoItem {Text = text} + ); + + return new TodoItemDto + { + Id = todoItem.Id, + Text = todoItem.Text + }; +} +```` + +Repository's `InsertAsync` method inserts the given `TodoItem` to database and returns the same `TodoItem` object. It also sets the `Id`, so we can use it on the returning object. We are simply returning a `TodoItemDto` by creating from the new `TodoItem` entity. + +Finally, we can simple implement the `DeleteAsync` as the following code block: + +````csharp +public async Task DeleteAsync(Guid id) +{ + await _todoItemRepository.DeleteAsync(id); +} +```` + +The application service is ready to be used from the UI layer. + +## User Interface Layer + +It is time to show the todo items on the UI! Before starting to write the code, it would be good to remember what we are trying to build. Here, a sample screenshot from the final UI: + +![todo-list](todo-list.png) + +> **We will keep the UI side minimal for this tutorial to make the tutorial simple and focused. See the [web application development tutorial](../Part-1.md) to build real-life pages with all aspects.** + +### Index.cshtml.cs + +Open the `Index.cshtml.cs` file in the `Pages` folder of the *TodoApp.Web* project and replace with the following content: + +````csharp +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace TodoApp.Web.Pages +{ + public class IndexModel : TodoAppPageModel + { + public List TodoItems { get; set; } + + private readonly ITodoAppService _todoAppService; + + public IndexModel(ITodoAppService todoAppService) + { + _todoAppService = todoAppService; + } + + public async Task OnGetAsync() + { + TodoItems = await _todoAppService.GetListAsync(); + } + } +} +```` + +This class uses the `ITodoAppService` to get the list of todo items and assign the the `TodoItems` property. We will use it to render the todo items on the razor page. + +### Index.cshtml + +Open the `Index.cshtml` file in the `Pages` folder of the *TodoApp.Web* project and replace with the following content: + +````xml +@page +@model TodoApp.Web.Pages.IndexModel +@section styles { + +} +@section scripts { + +} +
+ + + + TODO LIST + + + + + +
+ + +
+ + +
    + @foreach (var todoItem in Model.TodoItems) + { +
  • + @todoItem.Text +
  • + } +
+
+
+
+```` + +We are using ABP's [card tag helper](../../UI/AspNetCore/Tag-Helpers/Cards.md) to create a simple card view. You could directly use the standard bootstrap HTML structure, however the ABP [tag helpers]() make it much easier and type safe. + +This page imports a CSS and a JavaScript file, so we should also create them. + +### Index.js + +Open the `Index.js` file in the `Pages` folder of the *TodoApp.Web* project and replace with the following content: + +````js +$(function () { + + // DELETING ITEMS ///////////////////////////////////////// + $('#TodoList').on('click', 'li i', function(){ + var $li = $(this).parent(); + var id = $li.attr('data-id'); + + todoApp.todo.delete(id).then(function(){ + $li.remove(); + abp.notify.info('Deleted the todo item.'); + }); + }); + + // CREATING NEW ITEMS ///////////////////////////////////// + $('#NewItemForm').submit(function(e){ + e.preventDefault(); + + var todoText = $('#NewItemText').val(); + todoApp.todo.create(todoText).then(function(result){ + $('
  • ') + .html(' ' + result.text) + .appendTo($('#TodoList')); + $('#NewItemText').val(''); + }); + }); +}); +```` + +In the first part, we are registering to click events of the trash icons near to the todo items, deleting the related item on the server and showing a notification on the UI. Also, we are removing the deleted item from DOM, so we don't need to refresh the page. + +In the second part, we are creating a new todo item on the server. If it succeed, we are then manipulating DOM to insert a new `
  • ` element to the todo list. In this way, no need to refresh the whole page after creating a new todo item. + +The interesting part here is how we communicate with the server. It seems we are just calling some JavaScript functions like `todoApp.todo.delete(id)` and `todoApp.todo.create(todoText)`. + +#### Dynamic JavaScript Proxies & Auto API Controllers + + `todoApp.todo.delete(...)` and `todoApp.todo.create(...)` functions are dynamically created by the ABP Framework, thanks to the [Dynamic JavaScript Client Proxy](../../UI/AspNetCore/Dynamic-JavaScript-Proxies.md) system. These functions perform HTTP API calls to the server and return a promise, so you can register a callback to the `then` function as we've done above. + +However, you may ask that we haven't created any API Controller, so how server handles these requests? This question brings us the [Auto API Controller](../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to API Controllers by conventions. + +If you open the [Swagger UI](https://swagger.io/tools/swagger-ui/) by entering the `/swagger` URL in your application, you can see the TODO API: + +![todo-api](todo-api.png) + +### Index.css + +As the final touch, open the `Index.css` file in the `Pages` folder of the *TodoApp.Web* project and replace with the following content: + +````css +#TodoList{ + list-style: none; + margin: 0; + padding: 0; +} + +#TodoList li { + padding: 5px; + margin: 5px 0px; + border: 1px solid #cccccc; + background-color: #f5f5f5; +} + +#TodoList li i +{ + opacity: 0.5; +} + +#TodoList li i:hover +{ + opacity: 1; + color: #ff0000; + cursor: pointer; +} +```` + +This is a simple styling for the todo page. We believe that you can do much better :) + +## Conclusion + +In this tutorial, we've build a very simple application to warm up to the ABP Framework. If you are looking to build a serious application, please check the [web application development tutorial](../Part-1.md) which covers all the aspects of a real-life web application development. + +## Source Code + +You can find source code of the example application [here](https://github.com/abpframework/abp-samples/tree/master/TodoApp). \ No newline at end of file diff --git a/docs/en/Tutorials/Todo/todo-api.png b/docs/en/Tutorials/Todo/todo-api.png new file mode 100644 index 0000000000000000000000000000000000000000..f9a25f57b56d8191bb90b1aa676f086b88430d08 GIT binary patch literal 11114 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 OLPb#nS|V@u{yzY2=I+G+ literal 0 HcmV?d00001 diff --git a/docs/en/Tutorials/Todo/todo-list.png b/docs/en/Tutorials/Todo/todo-list.png new file mode 100644 index 0000000000000000000000000000000000000000..62f5a48065d2947116bc79208b26d7061535b024 GIT binary patch literal 12311 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 literal 0 HcmV?d00001