Tuesday, December 4, 2018

A20-Upgrading to Angular 7 and ASP.NET Core

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19Github Repo

Due to personal issues (new job, new country, India trip), I wasn’t able to blog.

Since I posted last time, Angular came out with Angular 7 and a new SDK for .NET Core also came out. Instead of continuing on the older version of Angular I decided to update everything.

I updated

Node to latest version v11.3.0.

NPM is at 6.4.1

I updated Visual Studio to latest and VS Code to latest version.

For updating angular to 7, I followed steps outlined at https://update.angular.io/

Updated Angular-cli globally and locally

Updated Angular Core and RxJs stuff.

Github warns you of vulnerabilities and everytime you run npm commands it shows you issues with packages. There were lot of package vulnerabilities so one by one I removed all of them and npm audit is not complaining anymore. 

After updating all the packages and running ng update for angular packages, I was getting errors when running dotnet run.

image

I had to update nuget package Microsoft.AspNetCore.SpaServices.Extensions. After updating it, I had to fix package.json scripts section’s start and build command to remove –extract-css flags.

Last issue I had to fix was related to certain rxjs operator usages in the application, eg. of, map, catch.

image

After fixing those I was able to compile and run the command dotnet run to view the application in the browser as I used to do before.

Thursday, July 12, 2018

A19–Building App using Angular and ASP.NET Core 2.1–Review Order Details

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 Github Repo

On training front, I finished Angular Reactive Forms course by Deborah Kurata on Pluralsight and I am watching Angular Services course by Brice Wilson.

Today, I was able to accomplish following.

1. Create a Review Order Page.

2. Create relevant server side API methods to return data

3. On submit button show confirmation page.

image

image

image

One of the things I had to change was make model names to be camelCase so when retrieving nested object they would display appropriately.

While there are many many issues with the app, I am able to do accomplish one workflow of being able to checkout products in a wizard style format. Notice that I am returning hard coded data for order review page. Once we figure out persistent store we can then return data from data store. There is also an issue with user identity. We want to associate orders with a person and we want to associate orders with unique id. All of that complexity can be handled piece by piece.

Next I want to tackle authentication piece.

That’s all I have for today. Checkout latest changes on github and website.

Tuesday, July 10, 2018

A18–Building App using Angular and ASP.NET Core 2.1–Reactive Forms, Submitting data

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 Github Repo

So I was able to accomplish following

1. Created classes to collect data from Form into Model for Shipping and Payment Pages.

2. Create CheckoutService to call Checkout controller methods

3. Created Controller methods for insert of shipping info and payment info

That’s all I have for today. Checkout latest changes on github and website.

Sunday, July 8, 2018

A17–Building App using Angular and ASP.NET Core 2.1–Reactive Forms Validation

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 Github Repo

I am currently watching Angular Reactive Forms course on Pluralsight by Deborah Kurata. I like Reactive Forms.

Today, I added form validation to shipping info page and payment info page.

image

image

Couple of things to note regarding behavior

1. Validation occurs as soon as you tab our or touch a control.

2. If you click on Next button then validation messages will be shown

3. Simple Regex pattern matching used for phone, card number, security code

4. Added dropdown for selecting card type and expiration month and year

5. Custom group validation implemented for validation Expiration month.

image

Special thanks to Loiane Groner for sharing code @ repo to show validation on button click. This trick and using a method to display validation messages saved a ton of repetitive code for me. I like it a lot.

Thanks to Debora Kurata for sharing code @ repo.

That’s all I have for today. Checkout latest changes on github and website.

Wednesday, July 4, 2018

A16–Building App using Angular and ASP.NET Core 2.1–Reactive Forms

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 Github Repo

I finished watching Angular Routing course and I think that it is very powerful. I like multiple router-outlet, child routes and route guard concept. Route resolver is a good concept too but I am running into issues when implementing in another child route.

Today using reactive forms I have added forms to collect shipping and payment information. There is no validation logic in there right now.

Shipping Info Form

image

Payment Info Form

image

One of my pet peeve with Angular is dependency injection. I ran into an issue with a child route resolver using a service and I couldn’t figure out why it won’t resolve the service. I wish there was a better way to let us know about why it couldn’t resolve the service. Can we have Angular Dependency Injection best practice guide?

Alright everyone, that’s all I have for today. Checkout latest changes on github and website.

Sunday, July 1, 2018

A15–Building App using Angular and ASP.NET Core 2.1–Route Resolvers, Child Routes

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14 Github Repo

Past three days have been hectic so there were no posts.

I am currently watching Angular Routing pluralsight course by Debora Kurata. I learned about Route Resolvers and Child routes. I refactored product/edit, product/details, product/delete page to use route resolver. Next I wanted to finish checkout page but I wanted to have a wizard type flow. After learning about child routes, I added shipping info, payment details, order review and confirmation components. I also refactored shopping cart as part of wizard. Shopping cart is the first page in this wizard.

Now when you click on shopping cart icon to the top right of the app you will see.

image

At the top, you can see different stages as nav items. As you start clicking different nav items you will see respective components.

image

Below is our shopping-routing module.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ShoppingCartComponent } from './shopping-cart/shopping-cart.component';
import { CheckoutComponent } from './checkout/checkout.component';
import { CheckoutPaymentComponent } from './checkout-payment/checkout-payment.component';
import { CheckoutReviewComponent } from './checkout-review/checkout-review.component';
import { CheckoutConfirmationComponent } from './checkout-confirmation/checkout-confirmation.component';
import { CheckoutShippinginfoComponent } from './checkout-shippinginfo/checkout-shippinginfo.component';

const routes: Routes = [
{
  path: 'checkout', component: CheckoutComponent, children: [
    { path: '', redirectTo: 'shoppingcart',  pathMatch: 'full'},
    { path: 'shoppingcart', component: ShoppingCartComponent} ,
    { path: 'shippinginfo', component: CheckoutShippinginfoComponent },
    { path: 'payment', component: CheckoutPaymentComponent },
    { path: 'review', component: CheckoutReviewComponent },
    { path: 'confirmation', component: CheckoutConfirmationComponent }
  ]
}];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class ShoppingRoutingModule { }

There is one thing I learned about property pathMatch: ‘full’—you cannot add it wherever you like. Initially I added to checkout path, and then I added to different child paths and it wasn’t working. So I removed that property.

Other minor css improvements include navbar nav-item active styling.

image

One thing bugging me is responsiveness of top wizard navigation for checkout component. I want to figure best way to handle that. I am thinking to show full text with icon and on smaller screens just show icons. As shown below, you can see how bad the styling is on smaller screens—completely unacceptable.

image

Alright everyone, that’s all I have for today. Checkout latest changes on github and website.

Wednesday, June 27, 2018

A14–Building App using Angular and ASP.NET Core 2.1–Responsive Product Card and Shopping Cart

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13 Github Repo

Today’s post is again going to be brief. You might think that these posts are becoming boring and I don’t put more code. My goal is to work on this app just a little bit everyday and learn something everyday. I don’t get to spend a lot of time on this app since most of the time I am working late at night. Sometimes I might do a lot and sometimes not a whole lot. So my goal is just learn and share—even if it is one sentence that I watched a video.

I tried to make product card and shopping cart responsive. I added checkout-contact component and hooked up to checkout button. However, I didn’t implemented logic for collecting contact information. I am thinking of first completing entire navigation scenario of checkout process and then implement details of each page.

Alright that’s it. Checkout the code on github.

Tuesday, June 26, 2018

A13–Building App using Angular and ASP.NET Core 2.1–Updating Shopping Cart Quantity

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12 Github Repo

Today’s post is going to be brief. I added following functionality to Shopping Cart page.

When you increase quantity of any given product then,

1. Order sub total should get updated.

2. Order Quantity should be updated.

3. Cart total should be updated.

Since there is no database backend, I have to add extra logic to account for persistence. For example, to simulate accurate quantity and amount post deletion, I had to write custom server side logic. This is unnecessary once data store is in place.

image

After increasing quantity order sub total is updated.

image

There is one issue I am running into and that is when using ngModelChange on input element, the change event is firing twice which seems like bug to me or I am doing something wrong (I think later to be true).

That’s all for today, see ya next time.

Monday, June 25, 2018

A12–Building App using Angular and ASP.NET Core 2.1–Shopping Cart

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11 Github Repo

In the previous post, I started created Shopping Cart page where you could view products and remove products from Shopping Cart. Today, I want to fix a couple of things about Shopping Cart. If you added multiple products then we want to do following things.

1. Show Product along with quantity

2. Change Product quantity

3. Show Order Total

4. Update Order Total when product is deleted.

5. Do not show same product multiple times if product is ordered multiple times.

Below is the UI for new checkout experience.

image

If I remove product then order total is updated.

image

I created a complete different class for displaying products on Shopping Cart Page. I am calling it ShoppingCartProduct. In the ShoppingCartController, I am getting all products and then doing a group by into ShoppingCartProduct.

using A100.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;

namespace A100.Controllers
{
    [Route("api/[controller]")]
    public class ShoppingCartController : Controller
    {
        private static List<Product> shoppingCartProducts = new List<Product>() {
            new Product { Id = 1, Title = "XYZ1",Description = "Description XYZ 1 ", Price = 101,ImageUrl = "ImageUrl_XYZ1" },
            new Product { Id = 1, Title = "XYZ1",Description = "Description XYZ 1 ", Price = 101,ImageUrl = "ImageUrl_XYZ1" },
            new Product { Id = 1, Title = "XYZ1",Description = "Description XYZ 1 ", Price = 101,ImageUrl = "ImageUrl_XYZ1" },
            new Product { Id = 2, Title = "XYZ2",Description = "Description XYZ 2 ", Price = 200,ImageUrl = "ImageUrl_XYZ2" }
        };
        [HttpGet("[action]")]
        public IEnumerable<ShoppingCartProduct> Products()
        {
            var s = from y in shoppingCartProducts
                    group y by y.Id into grouping
                    let p = grouping.First()
                    select new ShoppingCartProduct { Id = grouping.Key,
                        Title = p.Title,
                        Quantity = grouping.Count(),
                        Price = p.Price,
                        Description = p.Description,
                        ImageUrl = p.ImageUrl,
                        TotalPrice = p.Price * grouping.Count() };
            return s.ToList();
        }

        [HttpPost("[action]/{id:int}")]
        public ActionResult Add(int id)
        {
            return new JsonResult("product added to cart");
        }
        [HttpPost("[action]/{id:int}")]
        public ActionResult Delete(int id)
        {
            return new JsonResult("product removed from cart");
        }
    }
}

I had to update relevant parts shopping-cart.component.ts as well.

That’s all I have for today. Please check source code on Github and ask questions if you have any.

Friday, June 22, 2018

A11–Building App using Angular and ASP.NET Core 2.1–Services and Component Refactoring

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 Github Repo

Yesterday, I added items to Shopping Cart and API to add products to Shopping Cart. Next step is to be able to checkout products from Shopping Cart and in order to do so I needed a page to display products in Shopping Cart. So Below are things, I was able to accomplish today.

1. Added Shopping Cart Component, Display Products in the cart, Remove products from Shopping Cart.

image

2. I added Shopping Module and Routing Module for that. Since after adding Shopping Module, I was running into issues related to ShoppingCartWidget component. NavMenu component was complaining that you have to declare in the main module. I moved ShoppingCartWidget component into Shared Folder and reference from there. I had to refactor little bit regarding that.

3. Added code to Shopping Service related to removing product from shopping cart.

There are couple of things, I wanted to share that I liked. I switch between VS Code and Visual Studio for this project and I am in love with VS Code. Today I installed few extensions for VS and it makes your job much easier. Below are the ones I use for Angular Development.

1. Angular 6 Snippets – Mikael Morlund

2. Angular Files – Alexander Ivanichev

3. Angular Language Service – Angular

4. Angular V6 Snippets – John Papa

5. Debugger for Chrome – Microsoft

6. TSLint – Egamma

7. SASS – Robin Bentley

Angular Language Service extension and snippets is by far my favorite one. But they all helped me a lot. VS Code is so light weight. I like it a lot.

On learning path I am intending on finishing below courses

1. Learning Angular Routing by Debora Kurata on Pluralsight

2. Implementing and Securing an API with ASP.NET Core by Shawn Wildermuth on Pluralsight

See ya next time. And leave comments if you like anything or have any suggestion.

Code on GitHub.

Thursday, June 21, 2018

A10–Building App using Angular and ASP.NET Core 2.1–Services, Events and Cross Component Communication

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, A9 Github Repo
Today, I was able to accomplish few things,
1. Added Shopping service that adds product and updates shopping cart
2. Established cross component communication via Shopping Service (Home Component –> Add To Cart –> Updates Shopping Cart
3. Created API for adding and getting products from ShoppingCart Controller. I am returning hard coded products and hence you will always see two shown at the top right.
Right now I didn’t wanted to create any database backend. I want to just make sure client server interaction is in sync. Once I like how everything is structured then I will invest time into adding database layer. Below is code for Shopping Service.
import { Injectable, Inject } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Product } from '../product/product';
import { catchError, map, tap,last } from 'rxjs/operators';
import 'rxjs/add/observable/throw';
import { of } from 'rxjs/observable/of';
import { Observable } from 'rxjs/Observable';
const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json'
  })
};
@Injectable()
export class ShoppingService {

  private _baseUrl: string;
  private cartQuantitySource = new BehaviorSubject(0);
  currentCartQuantity = this.cartQuantitySource.asObservable();

  private _addProductToShoppingCart: string = "api/ShoppingCart/Add/";
  private _getProductsFromShoppingCart: string = "api/ShoppingCart/Products";
  constructor(private _http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    this._baseUrl = baseUrl;
    this.updateCartQuantity(); 
  }

  updateCartQuantity() {
    this._http.get<Product[]>(this._baseUrl + this._getProductsFromShoppingCart).subscribe(products => {
      this.log(`getting products from shopping cart`);
      this.cartQuantitySource.next(products.length);
    });
  }

  addProductToCart(product: Product) {
    this._http.post(this._baseUrl + this._addProductToShoppingCart + product.id, product, httpOptions).subscribe(x => {
      this.log(`added Product To Shopping Cart`);
      this.updateCartQuantity();
    });    
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      console.log(error); //log to console instead       
      this.log(`${operation} failed: ${error.message}`);
      return Observable.throw(error || 'Server error');
    };
  }
  private log(message: string) {
    console.log("Shopping Service " + message);
  }
}

One of the things, I am not liking is how api urls are hard coded as strings. This is something I want to improve upon. I will put them inside an injectable service which has all the urls.
Next thing I want to learn is authentication and authorization with ASP.NET Core.

Wednesday, June 20, 2018

A9–Building App using Angular and ASP.NET Core 2.1–Font-awesome, Pagination and Layout

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, A8, Github Repo

Today, I got carried away with home page layout and wasn’t able to fix communication between components. I spent trying to add pagination using some blogpost but then I discovered ngx-pagination. Below are things I was able to do.

1. Added pagination using ngx-pagination npm package it was pretty straight forward

2. Added font-awesome npm package so I could add shopping cart icon.

3. Added pagination to home page and products page

4. Added shopping-cart-widget component for displaying cart information

image

Next, I want to fix communication between components, ie. when you click on add to cart button it should add items to cart and call server side api method.

See ya next time.

Tuesday, June 19, 2018

A8–Building App using Angular and ASP.NET Core 2.1–SASS and Responsive Layout

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, Github Repo

Today, I could accomplish very little.

1. Fixed cards layout for home page

I like to put borders and see how where the boxes are.

image

As we change screen size, we can see responsive design at work.

image

Another one

image

image

Alright I messed this one up, I want to make this look different. However, I am running out of time for today.

image

2. From the screenshots above, menu has been fixed and is also responsive.

3. Using SASS syntax was something new—you don’t have to put {} and ; and indentation like python. So I will have to get used to this syntax.

Next, I will have to continue fixing home page styling and then I will follow up on adding more product information. I am excited to work on server side logic.

See ya next time.

Monday, June 18, 2018

A7–Building App using Angular and ASP.NET Core 2.1–Bootstrap 4, SASS, Cleanup

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5, A6, A7, Github Repo

On training side, I finished watching Beginner Path for Angular on Pluralsight. I learnt some nice things about Angular CLI. I didn’t knew that Angular app can be created using SASS, CSS or LESS as default way of creating style files. Dry run option is awesome. I always liked how PowerShell had –WhatIf flag and every CLI should have these types of commands.

Let’s cover all the things I was able to accomplish today.

1. Refactored app.module.ts file to make it leaner. I moved all product related components, routes and services into product module. In the image below, on the left everything in red was moved into product module.

image

2. Set the default style extension to be SASS and renamed all .css files to .sass. Right now I didn’t not create any styles into any sass file. Ahem, have to learn first right. Actually, I heard it is not very different than .less so will see how sass is. I had to delete navmenu component styles that were created by default template.

image

3. While I have worked with Bootstrap 3 a lot, I wanted to learn Bootstrap 4 in this project so I updated to Bootstrap 4. When you install Bootstrap 4 in an angular project, npm doesn’t install jquery, popper.js libraries so, I had to install those. I had to fix styling for home page and navigation to use Bootstrap 4.

image

4. Other visual and layout changes includes moving nav menu to top, moving home page content to about page, adding products to home page for people to view products on sale.

image

You can see home page with product cards. The UI is all messed up right now. There are many changes need to be made to how cards are displayed. The bottom card is completely hideous—taking up whole page.

image

5. Bug fix. In product.service.ts there was bug found in the handleError function which was returning default type. It should have thrown error. This prevented server side validation error from being displayed to our user.

image

So that’s all for today. The app is completely garbage right now but I am making progress. My next goals are as follows:

1. Make home page UI responsive, add style for product cards, make navigation menu responsive and add more data to display cards appropriately.

2. Add product description and other product related meta data, display that data accordingly on home page, add more complex data validation—using dates and dropdown.

See ya next time.

Friday, June 15, 2018

A6–Building App using Angular and ASP.NET Core 2.1– Cleanup, Host on Azure, CI and CD pipeline

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, A5 Github Repo

Here what I was able to accomplish today.

1. Cleanup default files created by Project template

2. Write readme document

3. Create CI and CD Pipeline using VSTS

4. Host on Azure App Service using Free Tier (link).

image

Hosted web site can be found here.

image

Thursday, June 14, 2018

A5–Building App using Angular and ASP.NET Core 2.1 – Services Dependency Injection

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, A4, Github Repo

Today my goal is to extract httpclient into a product service. And finish delete page.

Below is the code for extracted ProductService.

import { Injectable, Inject } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Product } from './product';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json'
  })
};

@Injectable()

export class ProductService {

  
  private _baseUrl: string;
  private _productListUrl: string = "api/Product/List";
  private _productInsertUrl: string = "api/Product/Insert";
  private _productEditUrl: string = "api/Product/Edit";
  private _productFindUrl: string = "api/Product/Find/";
  private _productDeleteUrl: string = "api/Product/Delete/";
  constructor(private _http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    this._baseUrl = baseUrl;
  }

  getProduct(id: number): Observable<Product> {
    return this._http.get<Product>(this._baseUrl + this._productFindUrl + id)
      .pipe(
        tap(product => this.log(`fetched product`)),
        catchError(this.handleError<Product>('getProduct'))
      );
  }

  getProducts(): Observable<Product[]> {
    return this._http.get<Product[]>(this._baseUrl + this._productListUrl)
      .pipe(
        tap(products => this.log(`fetched products`)),
        catchError(this.handleError('getProducts', []))
      );
  }

  insertProduct(product: Product): Observable<Product> {
    return this._http.post<Product>(this._baseUrl + this._productInsertUrl, product, httpOptions)
      .pipe(
        tap(products => this.log(`fetched products`)),
        catchError(this.handleError<Product>('insertProduct'))
      );
  }

  editProduct(product: Product): Observable<Product> {
    return this._http.post<Product>(this._baseUrl + this._productEditUrl, product, httpOptions)
      .pipe(
        tap(products => this.log(`fetched products`)),
        catchError(this.handleError<Product>('editProduct'))
      );
  }

  deleteProduct(product: Product): Observable<any> {
    return this._http.post<Product>(this._baseUrl + this._productDeleteUrl + product.id, product, httpOptions)
      .pipe(
        tap(products => this.log(`fetched products`)),
        catchError(this.handleError<Product>('deleteProduct'))
      );
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      console.log(error); // log to console instead      
      this.log(`${operation} failed: ${error.message}`);      
      return of(result as T);
    };
  }
   
  private log(message: string) {
    console.log("Product Service" + message);
  }
}

One of the things, I realized is that dotnet watch run sometimes will get stuck processing requests and it will feel like things have hanged. So I press Ctrl+C and dotnet watch will start processing things again. I have also hooked up Delete button with web api endpoint. Updated and working code is on Github Repo.

Next goal is to clean up default pages created by ASP.NET Core SPA template and host it on Azure website.

Wednesday, June 13, 2018

A4–Building App using Angular and ASP.NET Core 2.1 – Posting Form Values, Server-Side Validation, Displaying Error Messages

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, A3, Github Repo

Today, my goal is hook up submit button for Insert, Edit and Delete Pages with HttpClient and post form values to ASP.NET Core Web API backend.

Below is code for product-insert.component.ts file, the code for product-edit.component.ts is same. Initially I am using HttpClient directly inside component.

import { Component, OnInit, Inject } from '@angular/core';
import { Product, IProduct } from '../product';
import { HttpClient, HttpHeaders } from '@angular/common/http';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    'Authorization': 'my-auth-token'
  })
};


@Component({
  selector: 'app-product-insert',
  templateUrl: './product-insert.component.html',
  styleUrls: ['./product-insert.component.css']
})

export class ProductInsertComponent implements OnInit {

  public product: IProduct;
  private _baseUrl: string;
  constructor(private _http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    this.product = new Product("", 0);
    this._baseUrl = baseUrl;
  }


  onProductSave(product: IProduct) {
    console.log(JSON.stringify(product));
    this._http.post<Product>(this._baseUrl + 'api/Product/Insert', product, httpOptions)
      .subscribe(result => {
        console.log(result);
      }, error => console.log(error));
    
  }
  ngOnInit() {

  }

}

I tested that when I clicked Save button, http post is getting called and same object being returned. In the image below, you can see that first json object is from component and other one is returned from API call.

image

I want to add some server side validation. Let’s say that price of product should be greater than 100. If price is less than 100 then throw BadRequest from server and display to user that error.

  [HttpPost("[action]")]
        public ActionResult<Product> Insert([FromBody] Product product)
        {
            _validateProduct(product);
            if (ModelState.IsValid)
            {
                //TODO: Save Product to database.
                return product;
            }
            return BadRequest(ModelState);
        }

        private void _validateProduct(Product product)
        {
            if (product.Price < 100)
            {
                ModelState.AddModelError(nameof(Product.Price), $"Product price cannot be less than 100, you entered {product.Price}");
            }
        }

In the code above, if the product price is less than 100, I am adding model error for key Price and message. This message we will have to show it to the user.

import { Component, OnInit, Inject } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { Product, IProduct } from '../product';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    'Authorization': 'my-auth-token'
  })
};


@Component({
  selector: 'app-product-edit',
  templateUrl: './product-edit.component.html',
  styleUrls: ['./product-edit.component.css']
})
export class ProductEditComponent implements OnInit {

  public errors: string[];
  public product: Product;
  id: number;
  private _baseUrl: string;
  constructor(private _http: HttpClient, private _activeRoute: ActivatedRoute, @Inject('BASE_URL') baseUrl: string) {
    this._baseUrl = baseUrl;
    this.id = this._activeRoute.snapshot.params['id'];
    this._http.get<Product>(baseUrl + 'api/Product/Find/' + this.id).subscribe(result => {
      this.product = result;
    }, error => console.log(error));


  }

  onProductSave(product: IProduct) {
    console.log(JSON.stringify(product));
    this._http.post<Product>(this._baseUrl + 'api/Product/Edit', product, httpOptions)
      .subscribe(result => {
        console.log(result);
      }, error => {
        console.log(error.error);
        if (error.status === 400) {
          let allErrors = error.error;
          console.log(allErrors);
          for (var fieldName in allErrors) {
            if (allErrors.hasOwnProperty(fieldName)) {
              this.errors.push(allErrors[fieldName]);
            }
          }
        }
      });
  }

  ngOnInit() {
    this.errors = [];
  }

}

I found this post by Carl and I am following his post to show error messages returned. Thank you Carl.

<br />
  <div class="alert alert-danger" role="alert" *ngIf="errors.length > 0">
    <ul>
      <li *ngFor="let error of errors">
        {{ error }}
      </li>
    </ul>
  </div>

This is displayed as shown in the image below.

image

I am displaying server side error message like below and marking the control as invalid as shown below.

import { Component, OnInit, Inject } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { Product, IProduct } from '../product';
import { FormControl, AbstractControl } from '@angular/forms';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    'Authorization': 'my-auth-token'
  })
};


@Component({
  selector: 'app-product-edit',
  templateUrl: './product-edit.component.html',
  styleUrls: ['./product-edit.component.css']
})
export class ProductEditComponent implements OnInit {

  public errors: string[];
  public product: Product;
  id: number;
  private _baseUrl: string;
  constructor(private _http: HttpClient, private _activeRoute: ActivatedRoute, @Inject('BASE_URL') baseUrl: string) {
    this._baseUrl = baseUrl;
    this.id = this._activeRoute.snapshot.params['id'];
    this._http.get<Product>(baseUrl + 'api/Product/Find/' + this.id).subscribe(result => {
      this.product = result;
    }, error => console.log(error));


  }

  onProductSave(productForm: any) {
    console.log((productForm));
    productForm.controls;
    let product = productForm.value;
    
    this._http.post<Product>(this._baseUrl + 'api/Product/Edit', product, httpOptions)
      .subscribe(result => {
        console.log(result);
      }, error => {
        console.log(error);
        console.log(error.error);
        if (error.status === 400) {
          let allErrors = error.error;
          for (var fieldName in allErrors) {
            if (allErrors.hasOwnProperty(fieldName)) {
              if (productForm.controls[fieldName]) {
                productForm.controls[fieldName].markAsTouched();
                productForm.controls[fieldName].setErrors({ invalid: true });
                this.errors.push(allErrors[fieldName]);
              } 
            }
          }
        }
      });
  }

  ngOnInit() {
    this.errors = [];
  }

}

This way the field is marked as invalid. I would like to show message below the field but it is taking longer for me to figure out today.

image

So that’s it folks for today, you can find the code on Github.

Next goal is to extract httpclient into a product service. And finish delete page.

Tuesday, June 12, 2018

A3–Building App using Angular and ASP.NET Core 2.1 – Form Validation

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. Links to previous posts –> A1, A2, Github Repo

Today, my goal was adding form validation to form controls. I added validation to Insert and Edit pages for Product. Validation on both the pages is very similar.

Add Product Validation

image

Same page but validation changes if you delete price and keep it null.

image

I learnt couple of things today regarding validation and forms.

1. There are many things to remember in hooking up things with form. For example, creating multiple validation is not that straight forward.

2. Out of the box there are couple of validators but real world scenarios almost always require you to have custom validation.

3. I wish there was an alternative to template variable. I do not like creating these variable on input fields. From an api standpoint it would have been nicer if everything was part of ngModel.

These are my naïve observations and stupid opinions based upon my limited knowledge regarding Angular internals.

Regarding my app, I am realizing that there is more code common between add and edit component. Perhaps I could utilize some shared component here. I am not too concerned with this right now. To get good grasp at validation, I am going to add more fields later.

Next goal is to be able to submit edit, insert, delete product using ASP.NET Web API as backend. Until then have a good night. And code is on GitHub.

Monday, June 11, 2018

A2–Building App using Angular and ASP.NET Core 2.1 – GitHub & Forms

This post is a part of a series of posts that I am writing as I am building an app using Angular and ASP.NET Core 2.1. The first post can be found here.

My first goal is to put this code on GitHub so people can follow progress and goof ups. Here is the link. The repo is called A100. Why A100 name? Because I couldn’t come up with a better name. There is no logic. Everything can be changed at any time in software so I just picked something and moved on.

You can clone it into a folder and if you have latest .NET Core SDK 2.1 installed you will be able to run the project as shown below.

PS M:\github\A100\src\A100> dotnet watch run

dotnet watch run is the best thing about building .NET web apps. You can make changes to file and see your website updated. No need to keep refreshing.

There is just one issue with dotnet watch when working with Angular and ASP.NET Core. And that is multiple urls. In the image below, there are three ports listening 5001 (https), 5000 and some random port generated by ng 55267.

image

You can use any url to test your application.

Next I am creating different pages edit, insert, details for viewing product information.

Details Page

image

Add New Page

image

Edit Product Page

image

Delete Confirmation Page

image

Product List Page

image

For all the methods, I am doing console.log as shown below.

image

One of the things that tripped me off was on initial page load when model was null. I had to add *ngIf=”product” at the root div. So that’s all I could accomplish today. The code is pushed to github.

Next I am going to tackle form validation.

Sunday, June 10, 2018

A1–Building App using Angular and ASP.NET Core 2.1

This post is a part of a series of posts that I will write as I build an app using Angular and ASP.NET Core 2.1. My goal with this series is not to show you how to do something but to build something little everyday and write about it. If I don’t build anything then I don’t write about it. I believe in concept of learn via building and learn via sharing. So let’s combine these two concepts. Please expect lots of mistakes being made by me and I hope you will correct them.

I have lot of experience building apps using AngularJS and ASP.NET MVC 5 but I wanted to learn Angular latest and ASP.NET Core 2.1. What I have done so far in this journey is listed below, so you have some background and you don’t assume that I am smart.

1. Watched Angular: Getting Started course on Pluralsight by Deborah Kurata

2. Finished Angular Tutorial: Tour of Heroes

3. Watching Angular: Forms course on Pluralsight by Mark Zamoyta

4. Built an app to showcase products and stuff.

My environment looks like this

1. Visual Studio 2017 15.7.3

2. Powershell

3. VS Code Latest

4. ASP.NET Core 2.1

5. Angular cli version listed below

image

6. Angular versions 5.2.0

I wanted to have server side back-end technology as ASP.NET Core and wanted to combine Angular with it. In latest ASP.NET Core 2.1, there is a template for getting started with this type of thing.

image

After application project was created, I was excited and I wanted to create a new Angular component. I executed this command on the command line ng generate component product-list and got the friend message to run npm install first. So I ran npm install and then did ng generate component product/product-list and used to get some errors. I don’t recall. However, after deleting contents of node_modules folder it started working.

Tip: Don’t run npm install. Just click Run or hit F5 and let visual studio install all dependencies.

In earlier version of ASP.NET Core 2.0 runtime, creating components using Angular CLI wasn’t that straight forward. In 2.1 working with Angular Cli has been fixed. I like this.

By default when you run the application, you get counter page and fetch data page. The fetch data page shows you how to retrieve data from ASP.NET WEB API endpoint.

I want to create product related pages such as insert, edit, delete, list, details and use ASP.NET WEB API. So first I created Product controller and related methods for doing insert, edit, delete, list and details. I used attribute routing. For simplicity, I am not connecting it to any database. I just want working methods. Then I tested these methods using PostMan client. Below is my Product Controller.

 [Route("api/[controller]")]
    public class ProductController : Controller
    {
        private static List<Product> Products = new List<Product>() {
            new Product { Id = 1, Title = "XYZ1", Price = 1,ImageUrl = "ImageUrl_XYZ1" },
            new Product { Id = 2, Title = "XYZ2", Price = 2,ImageUrl = "ImageUrl_XYZ2" },
            new Product { Id = 3, Title = "XYZ3", Price = 3,ImageUrl = "ImageUrl_XYZ3" },
            new Product { Id = 4, Title = "XYZ4", Price = 4,ImageUrl = "ImageUrl_XYZ4" },
            new Product { Id = 5, Title = "XYZ5", Price = 5,ImageUrl = "ImageUrl_XYZ5" },
            new Product { Id = 6, Title = "XYZ6", Price = 6,ImageUrl = "ImageUrl_XYZ6" },
            new Product { Id = 7, Title = "XYZ7", Price = 7,ImageUrl = "ImageUrl_XYZ7" },
            new Product { Id = 8, Title = "XYZ8", Price = 8,ImageUrl = "ImageUrl_XYZ8" },
            new Product { Id = 9, Title = "XYZ9", Price = 9,ImageUrl = "ImageUrl_XYZ9" }
            
        };
        [HttpGet("[action]")]
        public IEnumerable<Product> List()
        {
            return Products;
        }

        [HttpGet("[action]/{id:int}")]        
        public ActionResult<Product> Find(int id)
        {
            var product = Products.Where(x => x.Id == id).FirstOrDefault();
            if (product != null)
            {
                return product;
            }
            return NotFound($"Product with id {id} was not found");
        }

        [HttpPost("[action]")]
        public ActionResult<Product> Edit([FromBody] Product product)
        {
            return product;
        }

        [HttpPost("[action]/{id:int}")]
        public ActionResult<Product> Delete(int id)
        {
            return Ok("Delete Successfull");
        }

        [HttpPost("[action]")]
        public ActionResult<Product> Insert([FromBody] Product product)
        {
            return product;
        }
    }

Next up, I tried to create product-list angular component using angular cli using command ng g c product/product-list. I wanted to create product related component inside product folder. Hence, I used product/product-list as my component’s name. I am just going to borrow code from fetch-data component to retrieve product list.

import { Component, OnInit, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
  public products: Product[];
  constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    http.get<Product[]>(baseUrl + 'api/Product/List').subscribe(result => {
      this.products = result;
    }, error => console.log(error));
  }
  ngOnInit() {
  }
}
interface Product {
  id: number;
  title: string;
  price: number;
  imageUrl: string;
}

Next up, I hooked up navigation and you can see all the products being displayed. For brevity, I am not listing all the steps or code. I am going to put all this on GitHub so you can see the code and progress I make. Because, it turns out blogging every step is going to be time consuming. [edit- Github Repo here]

image

Creating angular components for delete, details, edit and insert as shown below.

image

image

Creating edit, delete, details, insert action buttons on product-list html page and adding routerLink so we can take appropriate actions. Below is how the page looks now.

Tip: Route should not have any ending /. Have product/insert instead of product/insert/

image

I hooked up these buttons with their respective components created in earlier step. Right now I have not created an markup for these individual action pages. That’s all I could get done today.

Next goal is to put this on GitHub and finish creating insert, edit, delete, details features of products page. See you next time. [edit- Github Repo here]