#!/bin/zsh if [ $# -eq 0 ] ; then echo "Pass the name of project" exit 1 fi NAME="$1" mkdir $NAME cd $NAME dotnet new sln --name $NAME dotnet new angular -o $NAME -au Individual dotnet sln $NAME.sln add $NAME/$NAME.csproj open $NAME.sln
Showing posts with label Angular. Show all posts
Showing posts with label Angular. Show all posts
Saturday, August 15, 2020
Create Angular with authentication project on macOS
Friday, March 20, 2020
Angular Service
Simpler way to make Angular service available to component, just add providedIn: 'root'
Then on consuming component:
To make it more explicit:
Then on consuming component:
@Injectable({providedIn: 'root'})
export class ProductService {
Then on consuming component:
@Component({
selector: 'pm-products',
templateUrl: './product-list.component.html'
// no need to add provider
})
export class ProductListComponent {
constructor(private _productService: ProductService)
}
To make it more explicit:
@Injectable()
export class ProductService {
Then on consuming component:
@Component({
selector: 'pm-products',
templateUrl: './product-list.component.html'
providers: [ProductService] // explicitly add the service here
})
export class ProductListComponent {
constructor(private _productService: ProductService)
}
Wednesday, March 11, 2020
Extracting components from Angular Routes
When I forgot to declare (in declarations) the components used in Angular Routes, it resulted to error: NG8002: Can't bind to 'ngModel' since it isn't a known property of 'input'
I decided to make a helper function:
Problem is, it gives these errors:

To enable runtime goodness, we need to disable AOT compilation, add --aot=false on angular commandline. However, disabling AOT would cause two major inconveniences.
First inconvenience, we cannot use constants as keys on objects (e.g., Angular Route) anymore. Doing so would result to example error: ERROR in Cannot read property 'loadChildren' of undefined

We can rectify the problem by avoiding the use of constants as keys:

Second inconvenience when AOT is disabled, despite fullTemplateTypeCheck is set to true, Angular won't be able to check name of the object(and properties) you are binding to ngModel if the name has a typo or misspellings. Angular will still happily build your project even if your template has full of typos or misspellings, which will result to runtime errors.

On the screenshot above, productNameBlahMeh does not exist on Product interface, yet Angular still build the project. This is due to AOT being disabled.
Those two inconveniences greatly outweighs the safety net for committing typos (or spelling mistakes). const can prevent typo errors as it enforces the single source of names in the code. It's hard to rely on developers not making typo or misspelling mistakes. fullTemplateTypeCheck only works if AOT is enabled.
I decided to make a helper function:
function* getRoutesComponents(routes: Routes) {
for (const route of routes) {
if (route.component) {
yield route.component;
if (route.children) {
yield* getRoutesComponents(route.children);
}
}
}
}
Problem is, it gives these errors:

To enable runtime goodness, we need to disable AOT compilation, add --aot=false on angular commandline. However, disabling AOT would cause two major inconveniences.
First inconvenience, we cannot use constants as keys on objects (e.g., Angular Route) anymore. Doing so would result to example error: ERROR in Cannot read property 'loadChildren' of undefined

We can rectify the problem by avoiding the use of constants as keys:

Second inconvenience when AOT is disabled, despite fullTemplateTypeCheck is set to true, Angular won't be able to check name of the object(and properties) you are binding to ngModel if the name has a typo or misspellings. Angular will still happily build your project even if your template has full of typos or misspellings, which will result to runtime errors.

On the screenshot above, productNameBlahMeh does not exist on Product interface, yet Angular still build the project. This is due to AOT being disabled.
Those two inconveniences greatly outweighs the safety net for committing typos (or spelling mistakes). const can prevent typo errors as it enforces the single source of names in the code. It's hard to rely on developers not making typo or misspelling mistakes. fullTemplateTypeCheck only works if AOT is enabled.
Tuesday, March 10, 2020
NG8002: Can't bind to 'ngModel' since it isn't a known property of 'input'
This error will happen too even if the FormsModule is imported directly or indirectly (from shared module for example) in the feature module, if the imported component is not declared on declarations:

I followed Deborah Kurata's Angular Routing course, while I added the imported component ProductEditInfoComponent on Angular Route's component property, I forgot to add ProductEditInfoComponent on declarations property.
Adding the ProductEditInfoComponent on declarations property would solve the NG8002: Can't bind to 'ngModel' since it isn't a known property of 'input'. problem


I followed Deborah Kurata's Angular Routing course, while I added the imported component ProductEditInfoComponent on Angular Route's component property, I forgot to add ProductEditInfoComponent on declarations property.
Adding the ProductEditInfoComponent on declarations property would solve the NG8002: Can't bind to 'ngModel' since it isn't a known property of 'input'. problem

Sunday, March 8, 2020
TypeScript non-null assertion operator
Use non-null assertion operator if and only if you can assert that it will not result to null
If the parameter name passed to paramMap.get has a typo, the paramMap.get will return null. How can the developer really assert that the expression would not return null if the developer can't guarantee that the code has no typo?
product-resolver.service.ts:
Solution:
Since the 'id' parameter on route.paramMap.get is a parameter on Angular Routes, introduce a const for 'id'. This way, making a typo would be impossible, then we can validly assert that it would be impossible to obtain null from paramMap.get since we can only use parameter names on paramMap.get that are present on Angular Routes.
product-resolver.params.ts:
product.module.ts:
Code smell:
product-resolver.service.ts:
Using literal string (non-const) parameters on paramGet on non-null assertion expression would be a code smell as it is easy to make a typo when passing literal string, the expression will return null if there is a typo, thereby asserting non-null result is at best is weak. Consider any literal string as magic strings. Magic strings can be avoided by using const.
A developer using non-null assertion operator on expression that uses magic strings/numbers is a developer in hubris: "I never make typos in my entire life, promise!"
To remove that code smell on non-null assertion expression on paramMap.get, pass parameter name that was declared from const and Angular Routes:
product-resolver.service.ts:
If the parameter name passed to paramMap.get has a typo, the paramMap.get will return null. How can the developer really assert that the expression would not return null if the developer can't guarantee that the code has no typo?
product-resolver.service.ts:
@Injectable({
providedIn: "root"
})
export class ProductResolver implements Resolve<ProductResolved> {
constructor(private productService: ProductService) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<ProductResolved> {
const id = +route.paramMap.get('id')!;
// A power user error, or QA-induced error
if (isNaN(id)) {
const error = `Product id was not a number: ${id}`;
console.error(error);
// false: cancel the route
// null: continue, the component handle the null object
// navigate to error page: no built-in resolver mechanism for passing error
// messages out a route resolver to the prior or activated route.
return of({ product: null, error });
}
return this.productService.getProduct(id).pipe(
map(product => ({ product })),
catchError(error => {
const message = `Retrieval error: ${error}`;
return of({ product: null, error });
})
);
}
}
Solution:
Since the 'id' parameter on route.paramMap.get is a parameter on Angular Routes, introduce a const for 'id'. This way, making a typo would be impossible, then we can validly assert that it would be impossible to obtain null from paramMap.get since we can only use parameter names on paramMap.get that are present on Angular Routes.
product-resolver.params.ts:
export const PRODUCT_DETAIL_ID_PARAM = "id"; export const PRODUCT_RESOLVED = "productResolved";
product.module.ts:
import {
PRODUCT_DETAIL_ID_PARAM,
PRODUCT_RESOLVED
} from "./product-resolver.params";
const ROUTES: Routes = [
{ path: "products", component: ProductListComponent },
{
path: `products/:${PRODUCT_DETAIL_ID_PARAM}`,
resolve: { [PRODUCT_RESOLVED]: ProductResolver },
component: ProductDetailComponent
},
{
path: `products/:${PRODUCT_DETAIL_ID_PARAM}/edit`,
resolve: { [PRODUCT_RESOLVED]: ProductResolver },
component: ProductEditComponent
}
];
Code smell:
product-resolver.service.ts:
const id = +route.paramMap.get('id')!;
Using literal string (non-const) parameters on paramGet on non-null assertion expression would be a code smell as it is easy to make a typo when passing literal string, the expression will return null if there is a typo, thereby asserting non-null result is at best is weak. Consider any literal string as magic strings. Magic strings can be avoided by using const.
A developer using non-null assertion operator on expression that uses magic strings/numbers is a developer in hubris: "I never make typos in my entire life, promise!"
To remove that code smell on non-null assertion expression on paramMap.get, pass parameter name that was declared from const and Angular Routes:
product-resolver.service.ts:
const id = +route.paramMap.get(PRODUCT_DETAIL_ID_PARAM)!;
Sunday, November 24, 2019
Banana in a box for Angular 1.x code monkeys :)
Two-way databinding, used to be this simple in AngularJS 1.x:
Angular 2 made the two-way databinding explicit, which can be accomplished by either of the following:
Still pining for the old days? You can do Angular 1's terser approach in Angular 2:
That's called banana in a box. Just put parenthesis (a.k.a. banana) around ngModel, otherwise it won't work.
It's true, we are code monkeys :)
Using the ngModel approach produces an error if FormsModule is not imported:
To solve that, import FormsModule from "@angular/forms", a good place to import it is from app.module.ts, on entry point of the app.
<input ng-model="todo.completed" type="checkbox" />
Angular 2 made the two-way databinding explicit, which can be accomplished by either of the following:
<input [checked]="todo.completed" (input)="todo.completed = $event.target.checked" type="checkbox" />
<input [ngModel]="todo.completed" (ngModelChange)="todo.completed = $event" type="checkbox"/>
Still pining for the old days? You can do Angular 1's terser approach in Angular 2:
<input [(ngModel)]="todo.completed" type="checkbox" />
That's called banana in a box. Just put parenthesis (a.k.a. banana) around ngModel, otherwise it won't work.
It's true, we are code monkeys :)
Using the ngModel approach produces an error if FormsModule is not imported:
Can't bind to 'ngModel' since it isn't a known property of 'input'
To solve that, import FormsModule from "@angular/forms", a good place to import it is from app.module.ts, on entry point of the app.
Subscribe to:
Posts (Atom)