Thursday, December 3, 2020

Print PDF and Export Excel from RDLC in Asp.Net Core

This blog post is providing some more insight and the source code to a youtube tutorial, that I consider being worthwile looking at more closely.

Original Youtube video that inspired me:



Prerequisites:
1. Asp.Net Core MVC basics
2. Basic RDLC knowledge

Steps To follow:
1. Create an Asp.Net Core 3.1 MVC project
2. Add following Nuget Packages
  •     AspNetCore.Reporting
  •     System.CodeDom
  •     System.Data.SqlClient
3. Modify the Program.cs Class, by making sure it has the below function as:
  public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
                    webBuilder.UseWebRoot("wwwroot");
                    webBuilder.UseStartup<Startup>();
                });

4. Add a new project to the existing solution, a WinForm application. Create an empty RDLC report there, and also a DataSet for the report.

If your Visual Studio does not include the extension for RDLC reports, please take a look https://youtu.be/qhcg4dy43xk

5. Move the empty report to your MVC project, into wwwroot/Reports folder, and the dataset to a ReportDataset folder in the MVC project.

6. Configure the dataset and then the RDLC report:




The above report will have a string (text parameter) "prm" in it.

7. Create the HomeController in the following way:

 public class HomeController : Controller

    {

        private readonly ILogger<HomeController> _logger;


        private readonly IWebHostEnvironment _webHostEnvironment;


        public HomeController(ILogger<HomeController> logger, IWebHostEnvironment webHostEnvironment)

        {

            _logger = logger;

            _webHostEnvironment = webHostEnvironment;

            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

        }


        public IActionResult Index()

        {

            return View();

        }


        public IActionResult Print()

        {

            var dt = new DataTable();

            dt = GetEmployeeList();

            string mimetype = "";

            int extension = 1;

            var path = $"{this._webHostEnvironment.WebRootPath}\\Reports\\Employees.rdlc";

            Dictionary<string, string> parameters = new Dictionary<string, string>();

            parameters.Add("prm", "RDLC report (Set as parameter)");

            LocalReport lr = new LocalReport(path);

            lr.AddDataSource("dsEmployee", dt);

            var result = lr.Execute(RenderType.Pdf, extension, parameters, mimetype);

            return File(result.MainStream,"application/pdf");

        }


        public IActionResult Export()

        {

            var dt = new DataTable();

            dt = GetEmployeeList();

            string mimetype = "";

            int extension = 1;

            var path = $"{this._webHostEnvironment.WebRootPath}\\Reports\\Employees.rdlc";

            Dictionary<string, string> parameters = new Dictionary<string, string>();

            parameters.Add("prm", "RDLC report (Set as parameter)");

            LocalReport lr = new LocalReport(path);

            lr.AddDataSource("dsEmployee", dt);

            var result = lr.Execute(RenderType.Excel, extension, parameters, mimetype);

            return File(result.MainStream, "application/msexcel", "Export.xls");

        }

        private DataTable GetEmployeeList()

        {

            var dt = new DataTable();

            dt.Columns.Add("EmpId");

            dt.Columns.Add("EmpName");

            dt.Columns.Add("Department");

            dt.Columns.Add("BirthDate");

            DataRow row;


            for (int i = 1; i< 100; i++)

            {

                row = dt.NewRow();

                row["EmpId"] = i;

                row["EmpName"] = i.ToString() + " Empl";

                row["Department"] = "XXYY";

                row["BirthDate"] = DateTime.Now.AddDays(-10000);

                dt.Rows.Add(row);

            }

            return dt;

        }

       

    }

8. Then, add the view for the Home controller (Index.cshtml)

<div class="text-center">

    <h1 class="display-4">RDLC Print</h1>

    <div>

        <a href="../home/print" target="_blank" class="btn btn-primary">Print PDF</a>

        <a href="../home/export" target="_blank" class="btn btn-secondary">Export Excel</a>

    </div>

</div>


This will generate PDF and export excel, based on the dummy data we populated the report.

9. The result will be:






Sunday, November 29, 2020

Showing Wildfires on Google Maps with Blazor Server

One of my favorite web programming YT channels presented this idea during the past weeks. Traversy Media's tutorial was about showing Wildfires using React and Google Maps.

Please, have a look on his approach:


As I am checking out Blazor Server, I decided to give it a try, to reproduce something similar, using C# and Blazor Server.

The aim of this app is just to show the wildfires of the world, on a map centered on California, using the above mentioned technlogies.

Prerequisites:

- basics of Blazor server

- intermediate C#

- using free component for maps from Radzen Blazor

- using Nasa Web Api

The application is livewildfires.zoltanhalasz.net

Github Repo with code: https://github.com/zoltanhalasz/WildFiresBlazor

Steps for the application:

1. Create a Blazor Server App with Asp.Net Core 3.1

2. Install Blazor Radzen for Server: https://blazor.radzen.com/get-started

3. See the tutorial for the Httpclient in Blazor from Tim Corey: 



4. Our Api will be inserted in appsettings.json

  "NasaAPI": "https://eonet.sci.gsfc.nasa.gov/api/v2.1/categories/8"

Please visit the link to examine the structure of json data, that will be deserialized.

5. Create folder Data in the project and insert class named Event.cs

Have a look on my approach, how to deserialize the json string coming from Nasa, by preparing the corresponding structure of classes.

6. The page with the wildfires, will be using Google Maps Component, please study that also on Radzon Blazor https://blazor.radzen.com/googlemap

7. The main logic of the display is presented in the Index.razor component. I will not reproduce it here, since would be just a copy paste from my repo.

I hope this was useful and somebody learnt a bit of Blazor from this.

Tuesday, October 6, 2020

Simple Cryptocurrency App With Blazor Server Incl Excel Export

For some reason, I started to like developing with Blazor Server, mainly because the rapidity and simplicity of development. I tend to use some free component libraries to speed up development. I still want to mention that all my experience with Blazor Server is only on tutorial/experimental level.

This is just an application to learn Blazor Server, and familiarize with Cryptocurrencies, it has no other purpose.



Prerequisites for this app:

- basic Blazor Server (See my previous tutorials)

- install Radzen Components in your app see https://blazor.radzen.com/get-started

- using the C# wrapper for CoinPaprika Api (to get cryptocurrency info) https://github.com/MSiccDev/CoinpaprikaAPI

Code repository: https://github.com/zoltanhalasz/BlazorCoins

Application is live under: https://blazorcoins.zoltanhalasz.net/

The app works the following way:

1. the route /cointable will show the top 100 crypto currencies, using the API



2. clicking the detail per each currency, the route /coinhistory will show a chart and historical data for selected currency



3. the route /coingrid will show exactly the same info as 1) only in a Radzen Grid




Bonus:

The app has export excel capabilities, which can be achieved doing the following:

1. create wwwroot/js/DownloadExcel.js

function saveAsExcel(fileName, byteContent) {

    var link = document.createElement('a');

    link.download = fileName;

    console.log(fileName);

    link.href = 'data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,' + byteContent;

    document.body.appendChild(link);

    link.click();

    document.body.removeChild(link);

}

2. include the file reference at the bottom of _Host.cshtml, just below the other scripts

    <script src="/js/DownloadExcel.js"></script>

3. install EPPlus, latest, via Nuget Packages

4. in page /cointable (or where you need to export from excel), insert the markup for a button

 <button class="btn btn-primary" @onclick="GenerateExcel">Download</button>

5. include the following in the top of the page you want to use Excel Export :

@inject IJSRuntime iJSRuntime;

6. Write the handlers for GenerateExcel, in the code section of the page where you have the list that you need to export in Excel

private async Task DownloadExcel(IJSRuntime myJSRuntime)

    {

        byte[] file;


        if (coinList == null) return;


        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

        using (var package = new ExcelPackage())

        {

            var worksheet = package.Workbook.Worksheets.Add("Sheet1");

            worksheet.Cells.LoadFromCollection(coinList, true);

            package.Save();

            file = package.GetAsByteArray();

        }

        await myJSRuntime.InvokeAsync<List<CoinInfo>>("saveAsExcel", "CoinList.xlsx", Convert.ToBase64String(file));

    }


    private async Task GenerateExcel()

    {

        await DownloadExcel(iJSRuntime);

    }



Monday, October 5, 2020

Upload and Download Pdf files to/from MS SQL Database using Razor Pages

As most of my project applications are business related, and I still plan to create such applications, thought about the idea to store attached pdf invoices in a database.

Below is a simple sample application, using Asp.Net Core 3.1 and Razor Pages, for an invoice management system with pdf file upload/download.

The Github repo for the application is here.

The application is also online, can be tested out: https://uploadfile.zoltanhalasz.net/

Prerequisites:

- beginner/intermediate Razor Pages for Asp.Net Core, see study material here https://mydev-journey.blogspot.com/2019/11/razor-pages-not-for-shaving.html

- intermediate C# and SQL

- some basic Entity Framework Core.

My sources for learning were:

- an MVC version for the upload: https://tutexchange.com/how-to-upload-files-and-save-in-database-in-asp-net-core-mvc/

- the download, was discovered using various C# resources.

Firstly, we create the database named UploadFile and then a table:

CREATE TABLE [dbo].[Invoices](

[Id] [int] IDENTITY(1,1) NOT NULL,

[Number] [int] NOT NULL,

[Date] [datetime] NOT NULL,

[Value] [decimal](18, 2) NOT NULL,

[Attachment] [varbinary](max) NULL,

 CONSTRAINT [PK_Invoices] PRIMARY KEY CLUSTERED ([Id] ASCWITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

Steps for creating the application:
1. Create an Asp.Net Razor Pages project
.Net Core version 3.1

2. Scaffold the database into the models using https://marketplace.visualstudio.com/items?itemName=ErikEJ.EFCorePowerTools or simply copy my Data folder that is adding the necessary data structures 
Alternatively, you can use the more traditional caffolding method: https://www.entityframeworktutorial.net/efcore/create-model-for-existing-database-in-ef-core.aspx

Make sure that the model and dbContext  (called UploadFileContext) will be stored in Data folder.

3. Add to Startup.cs, ConfigureServices method:

 services.AddDbContext<UploadfileContext>(options =>
                  options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),           
                    sqlServerOptions => sqlServerOptions.CommandTimeout(100))
                    );

4. Create and Index page, that will show the list of invoices
- the page cshtml file will contain the listing of the invoices, together with the download, upload, and delete functionalities


- the PageModel class will contain the methods to deal with:

a. download the pdf file from the database:

public async Task<IActionResult> OnPostDownloadAsync(int? id)
{
            var myInv = await _context.Invoices.FirstOrDefaultAsync(m => m.Id == id);
            if (myInv == null)
            {
                return NotFound();
            }

            if (myInv.Attachment== null)
            {
                return Page();
            }
            else
            {
                byte[] byteArr = myInv.Attachment;
                string mimeType = "application/pdf";
                return new FileContentResult(byteArr, mimeType)
                {
                    FileDownloadName = $"Invoice {myInv.Number}.pdf"
                };
            }
}

b. delete attached file from database:

public async Task<IActionResult> OnPostDeleteAsync(int? id)
{
            var myInv = await _context.Invoices.FirstOrDefaultAsync(m => m.Id == id);
            if (myInv == null)
            {
                return NotFound();
            }

            if (myInv.Attachment == null)
            {
                return Page();
            }
            else
            {
                myInv.Attachment = null;
                _context.Update(myInv);
                await _context.SaveChangesAsync();
            }

            Invoices = await _context.Invoices.ToListAsync();
            return Page();
}

5. Add a page to create Invoice Data (this can be done via Razor Pages scaffolding),

and 

6. Create an Upload Page that will help with pdf file upload

This will have the file with markup, cshtml, containing the html tags for the form:
@page
@model UploadFile.Pages.UploadModel
@{
}

<h1>Upload Invoice</h1>


<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post" enctype="multipart/form-data">
            <div class="form-group">
                <div class="col-md-10">
                    <p>Upload file</p>
                    <input type="hidden" asp-for="@Model.ID" value="@Model.myID" />
                    <input asp-for="file" class="form-control" accept=".pdf" type="file" />
                </div>
            </div>
            <div class="form-group">
                <div class="col-md-10">
                    <input class="btn btn-success" type="submit" value="Upload" />
                </div>
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

And for the PageModel class, we will have the handler to deal with the file uploaded:

public class UploadModel : PageModel
{                  

        private readonly UploadfileContext _context;

        public UploadModel(UploadfileContext context)
        {
            
            _context = context;
        }
        public int ? myID { get; set; }

        [BindProperty]
        public IFormFile file { get; set; }

        [BindProperty]
        public int ? ID { get; set; }
        public void OnGet(int? id)
        {
            myID = id;
        }

        public async Task<IActionResult> OnPostAsync()
        {
            if (file != null)
            {
                if (file.Length > 0 && file.Length < 300000)
                {
                    var myInv = _context.Invoices.FirstOrDefault(x => x.Id == ID);

                    using (var target = new MemoryStream())
                    {
                        file.CopyTo(target);
                        myInv.Attachment = target.ToArray();
                    }

                    _context.Invoices.Update(myInv);
                    await _context.SaveChangesAsync();
                }

            }

            return RedirectToPage("./Index");
        }

}


7. The end result will be like this:





Sunday, June 7, 2020

Weather App With Google Maps Demo Using Blazor Server, HttpClient and Radzen Components

My favorite teacher for C# on Youtube is Tim Corey, and his latest material concerns HttpClient, using a Weather Forecast Api.
See his material, and check the code provided, as this is a the beginning step towards our application. My application is live: https://httpclientwithmaps.azurewebsites.net
Final project is: https://github.com/zoltanhalasz/HttpClientWithMaps The way the final application works:
1. map is centered in Central Europe
2. click on the map- we will see the neighboring cities with available weather data
3. click on a red bullet - (marker) - the available weather forecast will be displayed in the table on the right.

Prerequisites:
1. Dotnet Blazor Server Side Basics - see my previous tutorial
2. Check Radzen Controls for Maps - check the source
https://blazor.radzen.com/googlemap
3. Check the Weather Api - it's the same source as mentioned by Tim
https://www.metaweather.com/api/
Steps to follow:
A. Take the sample application as starting point from Tim (it's a Blazor Server Application)
B. Add Blazor Radzen to the project, as presented below:
https://blazor.radzen.com/get-started
C. Add the following Changes, described below:

1. Add another class to Model folder to track the locations (which will be represented as red dots on the map)
    public class LocationModel
    {
        public int distance { get; set; }      
        public string title { get; set; }
        public string location_type { get; set; }
        public int woeid { get; set; }
        public string latt_long { get; set; }
        public double latt { get; set; }
        public double _long { get; set; }
    }

2. The code is commented, to understand the main functions, you can copy the WeatherData.razor page content into your project. This contains the functionality described in the beginning.

Please check the map functionality and weather api in the prerequisites to understand it.

3. The left menu is slightly simplified versus the Tim version, you can copy or leave it.

Enjoy! Let me know your comments.

Friday, May 1, 2020

Simple Todo App with Blazor Server and Material Blazor

In order to make my journey in C# more interesting, I insert small projects where I can learn new things. The new target is now Blazor Server, a very interesting Web Technology from Microsoft.

I am trying to find small things to learn and add them to a bigger project later this year, perhaps.
My main tutors on the net were Tim Corey, and maybe Nick Chapsas. You can search them on youtube, they have great content.

The new application I have created is a regular todo app which uses:
- blazor server
- material design https://www.matblazor.com/
- a simple list (no database)

Prerequisites:
- asp.net core 3.1 installed on your machine
- intermediate C# and html

Code is under:
https://github.com/zoltanhalasz/TodoList_BlazorServer.git

The application is live: https://todolist-blazorserver.zoltanhalasz.net/todos

You can add material design to a blazor server project:
1.Install-Package MatBlazor
2.Add @using MatBlazor in main _Imports.razor
3.add to _Host.cshtml (head section)
<script src="_content/MatBlazor/dist/matBlazor.js"></script>
<link href="_content/MatBlazor/dist/matBlazor.css" rel="stylesheet" />

The toaster is added to the todo page: see instructions at: https://www.matblazor.com/Toast

I will explain some of the code and application below.

A. The main model class for the todos:


public class TodoModel
{
public int Id { get; set; }

public string Todo { get; set; }

public DateTime Deadline { get; set; }

public bool IsCompleted { get; set; }

}

B. The layout:
Please read the below examples
https://www.matblazor.com/TextField
https://www.matblazor.com/Checkbox
https://www.matblazor.com/DatePicker
https://www.matblazor.com/Button
See list of icons available:
https://www.matblazor.com/Icon
Toast, see tutorial example:
https://www.matblazor.com/Toast

C. The code-behind:

D. Final result:



Thursday, April 30, 2020

My Journey with Blazor Server

In my study of C# alongside Javascript, and working on my projects (asp.net core and WPF), I came across this technology called Blazor.


This attempts to make C# valid across back-end and front-end, possibly avoiding the use of Javascript on the front-end. Blazor, as a part of Asp.Net Core 3.0 and 3.1, has two flavors, Blazor Webassembly and Blazor Server-Side.

My preoccupation is the latter, as it is production ready. The result is, some asp.net applications that are very fast and responsive, and there are lots of free and beautiful components that can add nice design to the web apps.



The tutorials I checked and can recommend, are the following:
Tim Corey's material about Blazor Server:
- introduction : https://youtu.be/8DNgdphLvag
- components: https://youtu.be/JE0tQ4tx0Nc
- free resources: https://youtu.be/i1Kric5tqYk
A tutorial series on youtube from Nick Chapsas:
Checking the free resources I want to highlight now two of them:
1. Material Design Components: https://www.matblazor.com/
My small sample app is here, live.

2. Radzen Blazor Components: https://blazor.radzen.com/
 My small sample app is here, live:  

And I found another beautiful tutorial, which I did not yet check in detail:

https://www.syncfusion.com/ebooks/blazor-succinctly

Overall, I find Blazor Server-Side a very interesting idea, worth exploring further.

Saturday, March 28, 2020

HighCharts with Angular - Part 2 - Stock Portfolio with Dashboard

In continuation of previous post, now I try to implement the final chapter of the book, https://www.apress.com/gp/book/9781484257432.

The app is live: https://stock-portfolio.zoltanhalasz.net/
Zip repo of client side:



The back-end, which uses an In-Memory database, and Asp.Net Core Web Api, is based on Chapter 7, will use a Yahoo Finance Wrapper, and provide data to the Angular app, as shown in the Web API controller (see book starting with, pages 259).

The Asp.Net Core back-end is live under:

https://stockapi.zoltanhalasz.net/api/getstock

Zip Repo of server side:

I changed the back-end and front-end a little bit, correcting Typos, Formatting (indentation) and changing a little bit the main Stock class of the project.







HighCharts with Angular - Part 1 - Introduction

To continue the idea from the previous posts, my goal is to gather a number of libraries that can make my business applications look more professional, adding new functionalities and features.


One of these libraries is HighCharts, that can be integrated easily into Asp.Net and Angular (and Javascript) projects.

I would add here this great book which started my interest and whose projects I looked at and tried to implement some of its content.


For any Angular project, we can add the HighChart libraries using the below npm commands:
1.
npm install highcharts –save
This command will add Highcharts dependencies into your project.

2.
npm install highcharts-angular –save
The Highcharts angular wrapper is open source. It provides vibrant
and dynamic feature visualization for Highcharts within an Angular
application.


The example attached will be an updated (corrected, as there are some typos and formatting issues in the book) version of the Chapter 5 example: Angular-Highcharts UI Application (page 125).
I added into my Angular App the following examples also: page 140 - 159: DrillDown Event, LegendItem Event, CheckBoxClick Event.

My application is online:
https://highcharts-angular1.zoltanhalasz.net/

Code can be downloaded :
(you have to add npm install after unzipping it)

The following routes are active:
A. adding a new student with marks:
https://highcharts-angular1.zoltanhalasz.net/addmarks
B. after adding them, their marks will be present under the main link
https://highcharts-angular1.zoltanhalasz.net/



C. events with checkbox
https://highcharts-angular1.zoltanhalasz.net/checkbox
D. events with legenditem click
https://highcharts-angular1.zoltanhalasz.net/legenditem
E. events with drilldown
https://highcharts-angular1.zoltanhalasz.net/drilldown



It also uses a back-end service live under the link: https://studentapi.zoltanhalasz.net/
this application also implements the .Net Wrapper of the Highchart, shown in example at the end of Chapter 5.

It is based on the book, starting with page 160, also adding an in-memory database to serve the data needed by the api controller. This will provide the back-end for the angular project above, and is called in the service typescript file of the angular project.

The code of the back-end is in this zip repo.





Tuesday, March 10, 2020

Front-End Challenge from Colt Steele: Stepper Form

In the past weeks I reviewed a bit my front-end (html-css-javascript) lessons, and also found an interesting challenge lately. It is a vanilla js challenge by Colt Steele, published on Youtube:


My solution to it:
https://github.com/zoltanhalasz/StepperForm

Working link(live project):
https://codepen.io/zoltanhalasz/project/editor/ApPwKj

Explanation:
-I am using a structure with div's with classes and id's that can be targeted by Javascript DOM manipulation.
- the script uses lots of functions, and the getElementById used to target the classes/ids
- use hide/show for the stepper form via Javascript (manipulating DOM styles)

Recommended reading:
- Javascript DOM: https://www.w3schools.com/js/js_htmldom.asp
- CSS/Html: https://www.w3schools.com/html/default.asp

Monday, March 9, 2020

From Angular to Ionic - Todo App - Tutorial






This is the Ionic 5 version of the Todo app presented in previous posts, without applying the formatting and Web Api. My goal was to practice my Angular lessons from last year, and do this with the trendy Ionic framework.

Prerequisites:
a.) javascript/angular intermediate knowledge
b.)check the following Ionic documentation https://ionicframework.com/docs/components/
Especially: button, input, card, alert.
c.) And also please check the steps for creation of simple apps in Ionic:
https://ionicframework.com/getting-started/
d.) code is commented for a better understanding. It's the angular/typescript component file that contains the whole logic, described in the comments, see repo.

Web version is live under the link:
https://ionic5-todo.zoltanhalasz.net/










Saturday, March 7, 2020

Traversy Media Tutorial Transformed into Angular




The plain javascript version of this tutorial: https://mydev-journey.blogspot.com/2020/02/expense-tracker-from-traversy-media.html

The application is live: https://ng-expenses.zoltanhalasz.net/

Zipped Repo:

Prerequisites:
1. intermediate javascript/typescript
2.  before you check my tutorial, please check the following material: https://www.positronx.io/angular-7-httpclient-http-service/
3. back-end for this angular app is identical with the javascript version backend.

Full Stack Mini ToDo-App With Angular, HttpClient, API Controller and In-Memory Database

This tutorial is an Angular version of the plain Javascript one.



The back-end will be exactly identical, for simplicity will call the API from the previous tutorial, please study the above link for this.

The application was created from scratch, new Angular 9 application, with some inspiration from the below Angular HttpClient tutorial.

Prerequisites:
1. you must have Angular 9 (or 7,8) installed on your PC
2. basic / intermediate javascript/typescript
3. review above mentioned tutorials. Web api for back-end is identical.
4. the front-end, styling belong to original tutorial from Dennis Ivy, I just transposed here to Angular.
5. basic tutorial for Angular, which teaches some of the steps: https://www.positronx.io/angular-7-httpclient-http-service/

Application is live under: https://angulartodo.zoltanhalasz.net/

Zip Repo: here.

Steps for creating the app:

1. ng new todolist

2. styling
add bootstrap: npm install bootstrap

css file include it in Angular.json

"styles": [ "node_modules/bootstrap/dist/css/bootstrap.min.css", "styles.scss" ]

in the index html file, I will include some special fonts in the head
 <link href="https://fonts.googleapis.com/css?family=Montserrat&amp;display=swap" rel="stylesheet">

app.component.css will include the formatting from Dennis Ivy's original tutorial.(see repo)

3. create class

export class todomodel {

    constructor (
        public idnumber,
        public titlestring,
        public completedboolean){
            
        }
}

4. create service - I will not copy the lengthy code here.(see repo)
Some starting points: it is a very close copy of the api service from this tutorial (also mentioned above):  https://www.positronx.io/angular-7-httpclient-http-service/

The Api link reference will be identical with the plain javascript tutorial.
'https://todolist.zoltanhalasz.net/api/TodoModels'

5. add various references to app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule }   from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { TodoService } from './todo.service';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [TodoService],
  bootstrap: [AppComponent]
})
export class AppModule { }



6. app component html

<div class="container">
  <div id="task-container">
      <div id="form-wrapper">
          <form id="form" (ngSubmit)="onSubmit()" #todoForm="ngForm">    
                  <div class="flex-wrapper">
                    <div style="flex: 6">                      
                      <input type="text" class="form-control" id="title" required [(ngModel)]="mytodo.title" name="title"
                      #title="ngModel">
                    </div>             
                    <div style="flex: 1">
                      <button type="submit" id="submit" class="btn">Submit</button>     
                    </div>      
                  </div>                      
          </form>
      </div>
      <div id="list-wrapper">
        <div class="task-wrapper flex-wrapper" *ngFor="let item of mytodolist">
          <div style="flex:7">
            <span [className]="item.completed ? 'finish-title' : 'title'"             
            (click)="FinishTodo(item.id)">{{item.title}}</span>
          </div>
          <div style="flex:1">
            <button class="btn btn-sm btn-outline-info edit" (click)="Edit(item.id)">Edit </button>
          </div>
          <div style="flex:1">
            <button class="btn btn-sm btn-outline-danger delete" (click)="Delete(item.id)">Delete</button>
          </div>
        </div>
      </div>
  </div>
</div>
<!-- <router-outlet></router-outlet> -->


7. app.component.ts

import { ComponentOnInit } from '@angular/core';
import {todomodelfrom "./todomodel";
import { TodoService } from './todo.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  title = 'todolist';
  // when a task is being edited  
  edited = false;
  // initialize sample todo
  mytodo = new todomodel(0,'',false);
  // this array will always store list of todos retrieved from server
  mytodolist:  todomodel [];

  //injecting the dataservice
  constructor (private dataserviceTodoService) {
  }

  // submitting the form 
  onSubmit() {      
      this.saveTodo(this.mytodo);
      // resetting the mytodo value
      this.mytodo = new todomodel(0,'',false);
    }

  saveTodo(mytodotodomodel){
    // if it is not an editing
    if (!this.edited) {
      if (this.mytodo.title==''return;
      // saving new todo
        this.dataservice.createTodo(mytodo).subscribe(data=> {
          this.displayTodoList();
      });
    }
    // if we are editing an existing todo
    else {
      this.edited=false;
      console.log('this is being edited',mytodo);
            // update existing todo
      this.dataservice.updateTodo(this.mytodo.id,this.mytodo).subscribe(data =>
        {     
          this.displayTodoList();
        }       
        );
    }    
  }

  ngOnInit(){
    this.displayTodoList();
  }

  //this function retrieves the whole array of todos from server, using api service injected
  displayTodoList() {
    this.dataservice.getTodoList().subscribe(data =>
      {
        // as the Web Api doesn't sort the list of todos, we do here in the frontend
        this.mytodolist = data.sort((a,b)=> {
          if (a.id>b.idreturn -1;
          if (a.id<b.idreturn 1;
        });
        console.log('display'this.mytodolist);
      });
  }
  //deleting an existing todo
  Delete(idnumber) { // without type info
    console.log('delete'id);    
    this.dataservice.deleteTodo(id).subscribe(data =>{
        this.displayTodoList();
      });
  }
  //editing an existing todo
  Edit(eidnumber) { // without type info
    console.log('editing',eid);
    this.mytodo = this.mytodolist.filter(x=>x.id ==eid)[0];
    this.edited = true;   
  }

    //finalizing(crossing) an existing todo
  FinishTodo(eidnumber) { // without type info
    // console.log('finishing', eid);   
    const mytodofinished = this.mytodolist.filter(x=>x.id ==eid )[0];
    mytodofinished.completed =  !mytodofinished.completed ;
    //calling the update observable
    this.dataservice.updateTodo(eid,mytodofinished).subscribe(data =>{     
        this.displayTodoList();
      });
  }

}