Extremely Serious

Category: Javascript

Angular Data Bindings

Binding coordinates state transfer between the component's class and its template. The following table shows the different types of Angular data bindings.

TypeDescriptionDirectionExample
InterpolationEvaluates the expression between the double curly braces.One-way

(Component→Template)
<h1>{{header}}</h1>
Property BindingUpdates the property if there's a change from the bound component state.

This is typically denoted by the square bracket surrounding the target property.
One-way

(Component→Template)
<img [src]='imageURL'/>
Event BindingUpdates the bound component state if an event's was fired.

This is typically denoted by the parenthesis surrounding the event property.
One-way

(Component←Template)
<button (click)='onSave'>Save</button>
Two-Way BindingNormally use with the form elements.

This is typically denoted by the combined square and parenthesis surrounding the ngModel property.
Two-way

(Component↔Template)
<input type='text' [(ngModel)]='name'/>

JavaScript Prototypal Inheritance

The JavaScript's facility to provide inheritance is via prototype property of the constructor function (i.e. accessible via __proto__ in the instance context). Thus, we normally use the prototype to make properties and functions possible to be inherited. See the following code to do the inheritance properly.

Code 1 - Proper Way of Implementing Prototypal Inheritance
"use strict";

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

Person.prototype.middleName = "";

Object.defineProperty(Person.prototype, 'fullName', {
  get: function() {
    var name = (this.firstName||"");
    name += (name.length>0 ? " " : "") + (this.middleName||"");
    name += (name.length>0 ? " " : "") + (this.lastName||"");
      return name;
  }, 
  set: function(name) {
    var DELIM = " ";
    var names = (name||"").split(DELIM);
    this.firstName = names[0];
    this.lastName = names[1];
  }
});

function Employee(firstName, lastName, position) {
   Person.call(this, firstName, lastName);
   this.position = position||"";
}

Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;

var person = new Person();
person.fullName = "Ron Webb";
console.log(person.fullName);

var employee = new Employee("Ofelia", "Webb", "Manager");
console.log(employee.fullName);
console.log(employee.position);

Based on preceding code, the Employee is inheriting the Person via the following snippet:

Snippet 1 - Inhering the Person Class
Employee.prototype = Object.create(Person.prototype);

But, we should not stop there. We need to also specify the constructor to use the create the instance of Employee like the following snippet:

Snippet 2 - Specify the Constructor to Create the Employee Instance
Employee.prototype.constructor = Employee;

Lastly, in the constructor implementation of the Employee try to also call the constructor of the Person like the following snippet:

Snippet 3 - Call the Parent's Constructor
function Employee(firstName, lastName, position) {
   Person.call(this, firstName, lastName);
   this.position = position||"";
}

Using ES6 Syntactic Sugar for Inheritance

With ES6, this was greatly simplified because we don't need to deal with the prototype property of the constructor function like the following code:

Code 2 - ES6 implementation of Code 1
"use strict";

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.middleName = "";
  }
  
  get fullName() {
    var name = (this.firstName||"");
    name += (name.length>0 ? " " : "") + (this.middleName||"");
    name += (name.length>0 ? " " : "") + (this.lastName||"");
      return name;  
  }
  
  set fullName(name) {
    const DELIM = " ";
    var names = (name||"").split(DELIM);
    this.firstName = names[0];
    this.lastName = names[1];  	
  }
}

class Employee extends Person {
  constructor(firstName, lastName, position) {
   super(firstName, lastName);
    this.position = position||"";
  }
}

var person = new Person();
person.fullName = "Ron Webb";
console.log(person.fullName);

var employee = new Employee("Ofelia", "Webb", "Manager");
console.log(employee.fullName);
console.log(employee.position);

In ES6, we can now use the class keyword to define a class and a constructor method for its initialization. Regarding the constructor, we can now use the super method to call the parent constructor.

Moreover, implementing getter (i.e. using the get keyword before the function name) and setter (i.e. using the set keyword before the function name) are now very simple. Also the const keyword is now available to define immutable identifier just like what we can see on the fullName setter as we can see in the following snippet:

Snippet 4 - Using the Const Keyword
set fullName(name) {
  const DELIM = " ";
  var names = (name||"").split(DELIM);
  this.firstName = names[0];
  this.lastName = names[1];  	
}

All these enhancements in ES6 related to inheritance, in the background it still using the prototypical way. Remember these are just syntactic sugar.

Changing React Component State

Introduction

React renders component based on any changes on its state (i.e. data).

Updating State with Form Components

In React, a form input component controlled by it is known as controlled component. These components maintains their own state and update itself based on user input as depicted by the following code:

Code 1 - Controlled Text Input
const MessageView = (props) => {
  return(
    <h1>{props.message}</h1>
  );
}

class App extends React.Component {
  state = {
    message : ""
  };

  handleMsgChange = (event) => {
    this.setState({
      message: event.target.value
    });
  }
  
  render() {
    return(
        <div>
          <input type="text" placeholder="Type Something" value={this.state.message} onChange={this.handleMsgChange}/>
          <MessageView message={this.state.message}/>
      </div>
    );
  }
}

ReactDOM.render(<App />, mountNode);

The App component above has a message attribute in state as seen in the following snippet:

Snippet 1 - App Component State
state = {
  message : ""
};

We can bound the message attribute to the text input via the value attribute and listen to the changes on itself using the onChange attribute which in turn updates the state of the message like the following snippet:

Snippet 2 - Controlled Text Input
<input type="text" placeholder="Type Something" value={this.state.message} onChange={this.handleMsgChange}/>

The handleMsgChange that is bound to text input onChange attribute must update the message state of the React App component and could have the following implementation. This makes the React state as the single source of truth.

Snippet 3 - handleMsgChange Implementation
handleMsgChange = (event) => {
  this.setState({
    message: event.target.value
  });
}

This particular implementation will also trigger the re-render of the MessageView component since it is also dependent to the state of the message as we can see in the following snippet:

Snippet 4 - MessageView listening to the State of the Message
<MessageView message={this.state.message}/>

Updating State that may be Asynchronous

React might batch multiple setState function calls into a single update for performance. Thus the correct way to change the React state is by using the setState function that accepts a function instead of object like the following snippet:

Snippet 5 - Updating the React State
this.setState((prevState, props) => {
   //Do the state update here.
})

Let us try to create a reusable ButtonClear component that will clear value of the message attribute with the following snippet.

Snippet 6 - ButtonClear Component
const ButtonClear = (props) => {
  if (props.visible) {
    return(
        <button onClick={props.handleClear}>Clear</button>
    );
  }
  return(null); //Returns nothing
}

Based on the preceding snippet the ButtonClean component will only display the clear button if we tell it to make it visible via its visible attribute. Moreover, it is also expecting to have a handleClear implementation that will be bound to button's onClick attribute.

The handleClear implementation will be provided by the App component like the following snippet with the recommended usage of the setState() function:

Snippet 7 - App Component handleClear Implementation
handleClear = () => {
  this.setState((prevState, props) => {
    return {message: ""}; //Clears the message
  });
}

Thus we can use the ButtonClear component in the App component like the following snippet:

Snippet 8 - Using the ButtonClear in the App Component
<ButtonClear handleClear={this.handleClear} visible={this.state.message!=""}/>

We also instructed it to make the clear button visible only if the message is not empty.

The updated complete code with ButtonClear component can be seen as follows:

Code 2 - The Complete Code
const MessageView = (props) => {
  return(
    <h1>{props.message}</h1>
  );
}

const ButtonClear = (props) => {
  if (props.visible) {
    return(
        <button onClick={props.handleClear}>Clear</button>
    );
  }
  return(null);
}

class App extends React.Component {
  state = {
    message : ""
  };

  handleMsgChange = (event) => {
    this.setState({
      message: event.target.value
    });
  }
  
  handleClear = () => {
    this.setState((prevState, props) => {
      return {message: ""}; //Clears the message.
    });
  }
  
  render() {
    return(
        <div>
          <input type="text" placeholder="Type Something" value={this.state.message} onChange={this.handleMsgChange}/>
          <ButtonClear handleClear={this.handleClear} visible={this.state.message!=""}/>
          <MessageView message={this.state.message}/>
      </div>
    );
  }
}

ReactDOM.render(<App />, mountNode);

Note: We can run both Code 1 and Code 2 using jsComplete Playground