Angular walks through in ASP.NET Core project

Some notes about Angular application structure created using ASP.NET core template in Visual Studio;

ClientApp/src

This folder contains all the TypeScripts files related to Angular app. The whole client-side application source code is here.

The /ClientApp/src/app/assets/ folder keep application images and other asset files. These files will be copied over as-is in the /wwwroot/ folder upon application rebuild.

The /ClientApp/src/app/environment/ folder keep configuration files that target specific environments. For development, it’s environment.ts file and for production it’s environment.prod.ts.

Other root level files are;

1-index.html

The main HTML page that is served when someone visits the site.  The CLI automatically adds all JavaScript and CSS files when app is built. Therefore, we don’t’ see any <script> or <link> tags here.

2-karma.conf.js

This is application specific Karma configuration. Karma is a tool used to run Jasmine-based tests.

3-main.ts

The main entry point for application. Compiles the application with the JIT compiler and bootstraps the application’s root modules (AppModule) to run in the browser.

4-polyfills.ts

This provides polyfill scripts for browser support.

5-styles.css

A list of CSS files that supply styles for a project

6-test.ts

The main entry point for the project’s unit tests.

7-tsconfig.*.json

Project specific configuration options for various aspects of app. app.json for application-level, server.json for server level, and specs.json for tests. These options will override tsconfig.json file in the workspace root.

8-tslint.json

The TSLint configuration for the current project.

The ClientApp/src/app/ folder

This contains all of project’s logic and data and includes all Angular modules, services, components, templates and styles.

The basic building blocks of an Angular application is NgModules, which provides compilation context for Components. The role of NgModules is to collect related code into functional sets. Usually the whole Angular app is defined by a set of one or more NgModules.

An Angular app requires a root module, conventionally called AppModule. This tells Angular how to assemble the applications. This enables bootstrapping and starting the initialization life cycle. The remaining modules are known as feature-modules and serve a different purpose. This root module also contains a reference list of all available components.

This is a schema of the standard Angular Initialization Cycle. This can help us better visualize;

The main file bootstraps app.module.ts (AppModule), which then load the app.component.ts file (AppComponent), and later all other components whenever the application needs them.

The /ClientApp/src/app/ folder has the root module of any Angular app. This module is defined within the app.module.ts file. It is listed with a bunch of import statements and some arrays refrencing Components, other modules, providers an so on. We can see all of them here because root module is basically a reference file.

Server-side AppModule for SSR

The /ClientApp/src/app/app.module.ts file contains a BrowserModule.

import { BrowserModule } from '@angular/platform-browser';

This is used to enable the Angular Universal Server-Side Rendering (SSR).

imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' })

This is a technology that renders Angular applications on the server, provided that the back-end framework support it. .NET Core natively supports such convenient features. This is how the improved Angular initialization schema using SSR;

AppComponent

Angular app is basically a tree of Components working together. Components define views and use services to leverage. Service providers can be injected into Components as dependencies which makes the app code modular, reusable, and efficient. All of these components are conventially located in AppComponent.ts file. This file is located in /app/ root folder according to Angular folder structure conventions. All other components can be placed in sub-folder.

Usually there are three AppComponent files;

1-app.component.ts

This defines the component logic.

2-app.component.html

This defines the HTML templates associated with the AppComponent. Angular component can have an optional HTML file containing its UI layout. This is a good practice unless the component comes with a very minimal UI.

3-app.component.css

This defines all styles.

JavaScript Object Patterns

All object properties in JavaScript are public. There is no explicit way to indicate that a property shouldn’t be accessed from outside. Sometime we don’t want the data to be public. For example, when an object uses a value to determine some sort of state, modify that data without the objects’ knowledge throws the state management process.

One way to avoid this is by using naming conventions. For example, it’s quite common to prefix properties with an underscore (such as _name) when they are not intended to be public. However, there are other ways of hiding data that don’t rely on conventions.

The Module Pattern

There are many different ways to create and compose objects in JavaScript. While JavaScript does not include the formal concept of private properties, we can create data or functions that are accessible only from within an object. For singleton objects, we can use the module pattern to hide data from the outside world. we can use an immediately invoked function expression (IIFE) to define local variables and functions that are accessible only by the newly created object. Privileged methods are methods on the object that have access to private data. We can also create constructors that have private data by either defining variables in the constructor function or by using an IIFE to create private data that is shared among all instances.

var yourObject = (function() {

      // private data variables

      return {
          // public methods and properties
      };
}());

Here we are defining custom type that are keeping their private properties. This is similar to module pattern inside the constructor to create instance-specific private data.

function Student(name) {
            this.name = name;
        }
        Student.prototype = (function () {
            //private variables inside this closure scope
            var age = 25;   
            var myGrades = [93, 95, 88, 0, 55, 91];

            function getAge() {
                return age;
            }
            function growOlder() {
                age++;
            }

            function getAverage() {
                var total = 0;
                for (var i = 0; i < myGrades.length; i++) {
                    total += myGrades[i];
                }
                return avg = (total / myGrades.length);
            }

            function getGradeStatus() {
                var failingGrades = myGrades.filter(function (item) {
                    return item < 70;
                });

                return 'You failed ' + failingGrades.length + ' times.';
            }

            //revaling
            return {
                getAverage: getAverage,
                getGradeStatus: getGradeStatus,
                getAge: getAge,
                growOlder: growOlder
            };

        })();
var student1 = new Student("shahzad");
var student2 = new Student("ali");
student1.name		//returns "shahzad"
student1.getAge();	//returns 25
student1.growOlder();	//increment age 
student1.getAge();	//returns 26
student1.getAverage();	//returns 70.33333333333333
student1.getGradeStatus();	//returns "You failed 2 times."
student2.name			//returns "ali"
student2.getAge();		//returns 26
student2.getAverage();		//returns 70.33333333333333
student2.getGradeStatus()	//returns "You failed 2 times."

If we want private data to be shared across all instances, we can use a hybrid approach that looks like the module pattern but uses a constructor;

var Student = (function() {
    //everyone shares the same age
    var age = 20;   
    function IStudent(name){
        this.name = name;
    }
    
    IStudent.prototype.getAge = function() {
        return age;
    };
    
    IStudent.prototype.growOlder = function() {
        age++;
    };
    
    return IStudent;
}());

var student1 = new Student("shahzad");
var student2 = new Student("ali");
console.log(student1.name);	//returns shahzad
console.log(student1.getAge());		//returns 20
console.log(student2.name);		//returns ali
console.log(student2.getAge());		//returns 20
student1.growOlder();			//increment age
console.log(student1.getAge());		//returns 21
console.log(student2.getAge());		//returns 21

The IStudent constructor is defined inside an IIFE. The variable age is defined outside the constructor but is used for two prototype methods. The IStudent constructor is then returned and becomes the Person constructor in the global scope. All instances of Person end up sharing the age variable, so chaing the value with one instance automatically affects the other instance.

The Mixins Pattern

Mixins are a powerful way to add functionality to objects while avoiding inheritance. A mixin copies properties from one object to another so that the receiving object gains functionality without inheriting from the supplying object. Unlike inheritance, mixins do not allow you to identify where the capabilities came from after the object is created. For this reason, mixins are best used with data properties or small pieces of functionality. Inheritance is still preferable when you want to obtain more functionality and know where that functionality came from.

Scope-safe constructors

Scope-safe constructors are constructors that we can call with or without new to create a new object instance. This pattern takes advantage of the fact that this is an instance of the custom type as soon as the constructor begins to execute, which lets us alter the constructor’s behavior depending on whether or not you used the new operator.

function Person(name) {
    this.name = name;
}
Person.prototype.sayName = function() {
    console.log(this.name);
};
var person1 = Person("shahzad");		//note: missing “new”
console.log(person1 instanceof Person);		//returns false
console.log(typeof person1);			//returns undefined
console.log(name);				//returns shahzad

The name is created as a global variable because the Person constructor is called without new. Since this code is running in nonrestrict mode so leaving out new would not throw an error. The fact that constructor begins with capital letter should be preceded by new. What if we want to allow this use case and have the function work without new. We can implement a pattern like this;

function Person(name) {
    if (this instanceof Person) {
        //called with "new"
    } else {
        //called without new
    }
}

Let’s re-write our constructor logic;

function Person(name) {
    if (this instanceof Person) {
        this.name = name;
    } else {
        return new Person(name);
    }
}
var person1 = Person("shahzad");
console.log(person1 instanceof Person);		//returns true
console.log(typeof person1);			//returns object
console.log(person1.name);			//returns shahzad

The constructor is called recursively via new if new keyword is not used to create a proper instance of the object. This way following are equivalent;

var person1 = new Person(“shahzad”);
var person2 = Person(“shahzad”);

console.log(person1 instanceof Person);		//returns true
console.log(person2 instanceof Person);		//returns true

Creating new objects without using the new operator is becoming more common. JavaScript itself has several reference types with scope-sfe constructors, such as Object, Array, RegExp, and Error.

Resources

https://www.theodinproject.com/paths/full-stack-javascript/courses/javascript/lessons/factory-functions-and-the-module-pattern

JavaScript Inheritance

JavaScript does not offer classical inheritance structure where child class inherit properties of parent classes. JavaScript allows inheritance between objects with the help of prototype.

JavaScript built-in approach for inheritance is called prototype chaining, or prototypal inheritance. Prototype properties are automatically available on object instances which is a form of ineritance. Because prototype is also an object, it has its own properties and inherits properties from that. This is the prototype chain. An object inherits from its prototype, while that prototype in turn inherits from its prototype, and so on.

All objects inherit from Object. More specifically, all objects inherit from Object.prototype.

var person = {
    name: "shahzad"
};
var prototype = Object.getPrototypeOf(person);
console.log(prototype === Object.prototype);	//returns true

There are five method that appear on all objects through inheritance. They are inherited from Object.prototype;

hasOwnProperty() -> Determines whether an own property with the given name exists
propertyIsEnumerable() -> Determines whether an own property is enumerable
isPrototypeOf() -> Determines whether the object is the prototype of another
valueOf() -> Returns the value representation of the object
toString() -> Returns a string representation of the object

The last two are important when we need to make objects work consistently in JavaScript, and sometime we might want to define them ouself.

valueOf()

This method gets called whenever an operator is used on an object. By default, valueOf() simply returns the object instance. The primitive wrapper types override valueOf() so that it returns and string for String, a Boolean for Boolean and so on.

var now = new Date();
var earlier = new Date(2020,1,1);
console.log(now > earlier)	//returns true

now is the date representing the current time, and earlier is a fixed date in the past. When the greater-than-operator (>) is used, the valueOf() method is called on both objects before the comparison is performed. We can even subtract one date from another and get the difference in epoch time because of valueOf().

We can define our own valueOf() method if our objects are intended to be used with operators. We are not chaning how the operator works, only what value is used with operator’s default behavior.

toString()

The toString() method is called as a fallback whenever valueOf() returns a reference value instead of primitive value. It is also implicitly called on primitive values whenever JavaScript is expecting a string. For example, when a string is used as one operand for the plus operator, the other operand is automatically converted to a string. If the other operand is a primitive value, it is converted into a string representations (for example, true becomes “true”), but if its is reference value, then valueOf() is called.

var person = {
    name: "shahzad"
};
var message = "Name = " + person;	
console.log(message);	//returns Name = [object Object]

The code constructs the string by combining “Name =” with person. Since person is an object, its toString() method is called. The method is inherited from Object.prototype and returns the default value of “[object object]” in most JavaScript engines. If we are not happy with this value, we need to provide our own toString() method implementation.

var person = {
    name: "shahzad",
    toString: function() {
        return "[Name " + this.name + " ]"
    }
};
var message = "Name = " + person;
console.log(message);		//returns Name = [Name shahzad ]

Object Inheritance

The simples type of inheritance is between objects. All we have to do is specify what should be the new object’s [[Prototype]].

When a property is accessed on an object, the JavaScript engine goes through a search process. If the property is found on the instance, that property value is used. If the property is not found on the instance, the search continues on [[Prototype]]. If the property is still not found, the search continues to that object’s [[Prototype]], and so on until the end of the chain is reached. That chain usually ends with Object.prototype, whose [[Prototype]] is set to null.

We can also create objects with a null [[Prototype]] via Object.create();

var nakedObject = Object.create(null);
console.log("toString" in nakedObject);		//returns false
console.log("valueOf" in nakedObject);		//returns false

The naked object is an object with no prototype chain. That means built-in methods such as toString() and valueOf() aren’t present on the object. This object is a completely blank slate with no predefined properties, which makes it perfect for creating a lookup hash without potential naming collisions with inherited property names. There aren’t many other uses for an object like this. For example, any time you use an operator on this object, you’ll get an error “Cannot convert object to primitive value.”.

Constructor Inheritance

Object inheritance is the basis of constructor inheritance. Every function has a prototype property that can be modified or replaced. The property is automatically assigned to be a new generic object and has single own property called constructor. In effect, the JavaScript engine does the following for you;

//your write this
function MyConstructor(){
	//initialization
}

//JavaScript engine does this for you behind the scenes
MyConstructor.prototype = 
Object.create(Object.prototype, {
	constructor: {
		configurable: true,
		enumerable: true,
		value: MyConstructor,
		writable: true
}
});

MyConstructor is a subtype of Object, and Object is a supertype of MyConstructor. Prototype property is writable, we can change the prototype chain by overwriting it.

//first constructor
function Rectangle(length, width){
    this.length = length;
    this.width = width;
};

Rectangle.prototype.getArea = function() {
    return this.length * this.width;
};

Rectangle.prototype.toString = function() {
    return "[Rectangle " + this.length + " X " + this.width + "]";
};

//inherits from Rectangle
//second constructor
function Square(size) {
    this.length = size;
    this.width = size;
};

Square.prototype = new Rectangle();
Square.prototype.constructor = Square;

Square.prototype.toString = function() {
    return "[Square " + this.length + " x " + this.width + "]";
};

var rect = new Rectangle(5,10);
var square = new Square(6);
console.log(rect.getArea());	//returns 50
console.log(square.getArea());	//returns 36
console.log(rect.toString());	//returns [Rectangle 5 X 10]
console.log(square.toString());	//returns [Square 6 x 6]
console.log(rect instanceof Rectangle);	//returns true
console.log(rect instanceof Object);	//returns true
console.log(square instanceof Square);	//returns true
console.log(square instanceof Rectangle);	//returns true
console.log(square instanceof Object);	//returns true

In the above code, there are two constructors: Rectangle and Square. The Square constructor has it prototype property overwritten with an instance of Rectangle. No arguments are passed into Rectangle at this point because they don’t need to be used, and if they were, all instances of Square would share the same dimensions. The constructor property is restored on Square.prototype after the original value is overwritten.

rect is created as an instance of Rectangle, and square is created an an instance of Square. Both objects have the getArea() method because it is inherited from Rectangle.prototype. The square variable is considered as instance of Square as well as Rectangle and Object because instanceof uses the prototype chain to determine the object type.

Square.prototype doesn’t actually need to be overwritten. Rectangle constructor isn’t doing anything that is necessary for Square. The only relevant part is that Square.prototype needs to somehow link to Rectangle.prototype in order for inheritance to happen. That means, we can simplify the example by using Object.create();

//inherits from Rectangle
function Square(size) {
    this.length = size;
    this.width = size;
};
Square.prototype = Object.create(Rectangle.prototype, {
    constructor: {
        configurable: true,
        enumerable: true,
        value: Square,
        writable: true
    }
});
Square.prototype.toString = function() {
    return "[Square " + this.length + " x " + this.width + "]";
};
var square = new Square(5)
console.log(square.getArea());		//returns 25
console.log(square instanceof Square);	//returns true
console.log(square instanceof Rectangle);	//returns true
console.log(square instanceof Object);	//returns true
console.log(square.toString());		//returns [Square 5 x 5]

In this version, Square.prototype is overwritten with a new object that inherits from Rectangle.prototype, and the Rectangle constructor is never called. That means we don’t need to worry about causing an error by calling the constructor without arguments anymore.

Always make sure that you overwrite the prototype before adding properties to it, or you will lose the added methods when the overwrite happens.

Accessing Supertype (Base) Methods

In our previous example, the Square type has its own toString() method that shadown toString() on the prototype. What if we want to use base type method? JavaScript allows you to directly access the method on the supertype’s prototype and use either call() or apply() to execute the method.

Replace this;

Square.prototype.toString = function() {
    return "[Square " + this.length + " x " + this.width + "]";
};

With this;

Square.prototype.toString = function() {
    var text = Rectangle.prototype.toString.call(this);
    return text.replace("Rectangle", "Square");
};
var square = new Square(5)
console.log(square.getArea());	//returns 25
console.log(square.toString());	//returns [Square 5 X 5]

JavaScript Constructors and Prototypes

JavaScript lack classes, it turns to constructors and prototype to bring a similar order to objects.

Constructors

A constructor is simply a function that is used with new to create an object. There are built-in constructors for Object, Array and Functions. The advantage of constructors is that objects created with the same constructor contains the same properties and methods.

The constructor names should begin with capital letter, to distinguish them from other functions.

function Person() {
    //intentionally empty
}

This function is a constructor. The clue that Person is a constructor is in the name – the first letter is capitalized. Let’s create some instances;

var person1 = new Person();
var person2 = new Person();

The new operator automatically creates an object of the given type and returns it. We can use the instanceof operator to confirm object’s type.

console.log(person1 instanceof Person)		//returns true
console.log(person2 instanceof Person)		//returns true

We can also check the type of an instance using the constructor property. For generic objects (those created via an object literal or the object constructor), constructor is set to Object. For objects created with a custom constructor, constructor points back to that constructor function, in our case Person.

console.log(person1.constructor === Person);	//returns true
console.log(person2.constructor === Person);	//returns true

Let’s add some properties inside constructor;

function Person(name){
    this.name = name;
    this.sayName = function()
    {
        console.log(this.name);
    };
}

Now we can use the Person constructor to create objects with an initialized name property;

var person1 = new Person("shahzad");
var person2 = new Person("ali");
console.log(person1.name);		//returns shahzad
console.log(person2.name);		//returns ali

person1.sayName();			//returns shahzad
person2.sayName();			//returns ali

Make sure to always call constructors with new; otherwise it will be created on global objects. Constructors don’t eliminate code redundancy. For example, each instance has its own sayName() method even though sayName() doesn’t change. What if we have 100 instances of an object, then there are 100 copies of a function that do the exact same thing, just with different data.

If would be much more efficient if all of the instances shared one method, and then that method could use this.name to retrieve the appropriate data. This is where prototypes come in.

Prototypes

Think of prototype as a recipe for an object. Almost every function (except some built-in functions) has a prototype property that is used during the creation of new instances. This property is shared among all of the object instances. For example, hasOwnProperty() method is defined on generic Object prototype, but it can be accessed from any objects.

function Person(name){
    this.name = name;
}

Person.prototype.sayName = function() {
    console.log(this.name);
};

var p = new Person("shahzad");
var p1 = new Person("ali");

console.log(person1.name)	//returns "shahzad"
console.log(person2.name)	//returns "ali"
person1.sayName();		//returns “shahzad”
person2.sayName();		//returns “ali”

Let’s assign constructor property specifically on the prototype;

Person.prototype = {
    constructor: Person,
    
    sayName: function() {
        console.log(this.name);
    },
    
    toString: function() {
        return "[Person " + this.name + "]";
    }
};

var person1 = new Person("shahzad");
var person2 = new Person("ali");
console.log(person1 instanceof Person);		//returns true
console.log(person1.constructor === Person);	//returns true
console.log(person1.constructor === Object);	//returns false
console.log(person2 instanceof Person);		//returns true
console.log(person2.constructor === Person);	//returns true
console.log(person2.constructor === Object);	//returns false