React summary

React

Codeschool React summary of React.

React is a Javascript library for building UIs.
Why React?
React was built to solve one problem: building large
applications with data that changes over time.

Code of this post:

React is a Component-based Architecture, these component uses virtual-DOM#Virtual_DOM).
React support ES6 with babel.

  • Structure & scaffolding

There are different ways:

  1. The best way is Uses Creact React App
  2. Import librarys in html, for example this Structure:

    project
    │   index.html  
    │
    └───vendors
    │   │   react.js
    │   │   react-dom.js
    │   │   babel.js
    
    // In html file:
    
    <!DOCTYPE html>
    <html>
    <body>
     <script src="vendors/react.js"></script>
     <script src="vendors/react-dom.js"></script>
     <script src="vendors/babel.js"></script>
     <script type="text/babel" src="components.js"></script>
    </body>
    </html>
    
  • First React component

    A component in React works similarly to Javascript functions: It generates an output every time it is invoked.

    • component.js

      
      // Component
      class FirstReactComponent extends React.Component {
        render() {
          return( <div>Hello World!!</div> );
        }
      }
      
      // Render component
      ReactDom.render(
        <FirstReactComponent />, document.getElementById('root-app');
      );
      
    • index.html
      <!DOCTYPE html>
      <html>
      <body>
        <div id="root-app"></div>
      </body>
      </html>
      
  • JSX (Javascript XML) is a new markup to write React apps.

    • Markup looks similar to HTML, but ultimately gets transpiled to JavaScript function calls, which React will know how to render to the page.
    • Code written within curly braces is interpreted as literal JavaScript.
    • It is a common pattern to map arrays to JSX elements.

      // Component
      class FirstReactComponent extends React.Component {
      
      const now = new Date();
      
      render() { // The class in JSX is className
        return( <div className="hello">Hello World at { now.toTimeString() }</div> );
                                                // Code written in curly braces
                                                // gets interpreted as literal js.
      }
      }
      
      // Render component
      ReactDom.render(
      // React component are written in upper camel case
      <FirstReactComponent />, document.getElementById('root-app');
      );
      
  • Cominication between Component

    For example create two components: coment-box (parent) and comment (child), in html:

    <div class="comment-box"> <!-- Parent component: ComentBox -->
      <h3>Comments</h3>
      <h4 class="comment-count">2 comments</h4>
      <div class="comment-list">
    
        <!--Child Component: Comment  -->
        <div class ="comment">
          <p class ="comment-header">Anne Droid</p>
          <p class ="comment-body">
            I wanna know what love is...
          </p>
          <div class ="comment-footer">
            <a href="#" class ="comment-footer-delete">
              Delete comment
            </a>
          </div>
        </div>
        <!--Child Component: Comment  -->
    
      </div>
    </div><!-- Parent component: ComentBox -->
    

    Write Comment component:

    class Comment extends React.Component {
      render() {
        return(
          <div className ="comment">
            <p className ="comment-header">Anne Droid</p>
            <p className ="comment-body">
            I wanna know what love is...
            </p>
            // class becomes className in JSX
            <div className ="comment-footer">
              <a href="#" className ="comment-footer-delete">
                Delete comment
              </a>
            </div>
          </div>
        );
      }
    }
    

    Write the CommentBox Component:

      class CommentBox extends React.Component {
        render () {
          return (
            <div className="comment-box"> <!-- Parent component: ComentBox -->
              <h3>Comments</h3>
              <h4 className="comment-count">2 comments</h4>
              <div className="comment-list">
                // Child Component: Comment
                <Comment />
                <Comment />
              </div>
            </div>// Parent component: ComentBox
          );
        }
      }
    
    • Arguments in components –> Props

      • Accept Arguments:

        In child component Comment add props: author and body props.

          class Comment extends React.Component {
            render() {
              return(
                <div className ="comment">       <!-- Reading the autor prop (argument) -->
                  <p className ="comment-header">{this.props.author}</p>
                  <p className ="comment-body">
                    // Reading the body prop (argument)
                    {this.props.body}
                  </p>
                  // class becomes className in JSX
                  <div className ="comment-footer">
                    <a href="#" className ="comment-footer-delete">
                      Delete comment
                    </a>
                  </div>
                </div>
              );
            }
          }
        
      • Use props in the component

        Write the CommentBox Component with <Comment /> component in JSX and parsing props:

        class CommentBox extends React.Component {
          render () {
            return (
              <div className="comment-box"> <!-- Parent component: ComentBox -->
                <h3>Comments</h3>
                <h4 className="comment-count">2 comments</h4>
                <div className="comment-list">
        
                  // Passing Arguments to child Component: Comment
                  <Comment author="Morgan Serrano" body="Yeah!!" />
                  <Comment author="Bending González" body="Ohou Yeah!!" />
        
                </div>
              </div>// Parent component: ComentBox
            );
          }
        }
        
      • Example dynamics props && use Unique keys to improve performance:
        class CommentBox extends React.Component {
        render () {
          // get comments
          const comments = this._getComments();
        
          return (
            <div className="comment-box"> <!-- Parent component: ComentBox -->
              <h3>Comments</h3>
              <h4 className="comment-count">2 comments</h4>
              <div className="comment-list">
        
                // JSX knows how render arrays
                {comments}
        
              </div>
            </div>// Parent component: ComentBox
          );
        }
        
        _getComments() {
        
          const commentList = [
            { id: 1, author: 'Morgan McCircuit', body: 'Great picture!' },
            { id: 2, author: 'Bending Bender', body: 'Excellent stuff' }
          ];
        
          return commentList.map(( comment) => {
            return (                                             // add id in key to improve
              <Comment author={comment.author} body={comment.body} key={comment.id} />
          );
        });
        }
        }
        
    • Handling Data Changes With State

      In React, we don’t modify the DOM directly. Instead, we modify a component state object in
      response to user events and let React handle updates to the DOM.
      The state is a vital part of React apps, making user interface interactive.
      Events –> Update state –> DOM updates

      • Important on State:

        • State represents data that changes over time.
        • We declare an initial state in the component constructor.
        • We update state by calling this.setState();
        • Calling this.setState() causes our component to re-render.
        class CommentBox extends React.Component {
        
          // We set the initial state of our comments
          // in the class constructor
          constructor {
            // super() must be called in our constructor
            super();
        
            this.state = {
              showComments = false;
            }
          }
        
          render () {
            // get comments
            const comments = this._getComments();
        
            // Create list of comment if state is true
            let commentNodes;
        
            if (this.state.showComments){
              commentNodes = <div className="comment-list">{comments}</div>;
            }
        
            // button text based on component state
            let buttonText = 'Show comments';
            if (this.state.showComments) {
              buttonText = 'Hide comments';
            }
        
              return (
        
                <div className="comment-box">
                // Button that will togle state on click event
                // Important bind context
                <button onClick={this._handleClick.bind(this)}>{buttonText}</button>
        
                  <h3>Comments</h3>
                  <h4 className="comment-count">{this._getCommentsTitle(comments.length)}</h4>
                  {commentNodes}
                </div>
              );
            }
        
            _handleClick() {
                  // change state with setState method
              this.setState({  showComments: !this.state.showComments; });
            }
        
            _getComments() {
        
              const commentList = [
                { id: 1, author: 'Morgan McCircuit', body: 'Great picture!' },
                { id: 2, author: 'Bending Bender', body: 'Excellent stuff' }
              ];
        
              return commentList.map(( comment) => {
                return (                                            // add id in key
                  <Comment author={comment.author} body={comment.body} key={comment.id} />
              );
            });
          }
        }
        
    • SyntanticEvents and Refs

      Capture DOM events, for example submit in form.
      In order to ensure events have consistent properties across different browsers, React wraps the browser’s native events into synthetic events, consolidating browser behaviors into one API.

      Quick Recap:

      • We use React’s event system to capture user input, including form submissions and button clicks.
      • Refs allow us to reference DOM elements in our code after the component has been rendered.
      • Parent components can pass callback functions as props to child components to allow two-way
        communication.
      • SyntanticEvents are a cross-browser wrapper around the browser’s native event.

      Create Component CommentForm:

          class CommentForm extends React.Component {
            render() {
              return (
                <form className="comment-form" onSubmit={this._handleSubmit.bind(this)}>
                            // OnSubmit: Add on event listener to the sumbit even
                            // Important, bind thi
                  <label>Join the discussion</label>
                  <div className="comment-form-fields">
                                            // We will use these refs to access value from
                                            // inputs elements
                    <input placeholder="Name:" ref={(input) => this._author = input}/>
                    <textarea placeholder="Comment:" ref={(textarea) => this._body = textarea}>
                    </textarea>
                  </div>
                  <div className="comment-form-actions">
                    <button type="submit">Post comment</button>
                  </div>
                </form>
              );
            }
            _handleSubmit(event) {
              // Prevents page from reloading
              event.preventDefault();
              let author = this._author;
              let body = this._body;
      
              // This method has been passed as an argument to use in parent component (CommentBox)
              this.props.addComment(author.value, body.value);
            }          
          }
      

      Using CommentForm to Add Comments:

        class CommentBox extends React.Component {
      
          constructor {
            // super() must be called in our constructor
            super();
      
            this.state = {
              showComments = false;
              // Now part of the component's state
              comment = {
                id: this.state.comments.length + 1,
                author,
                body
              };
            }
          }
      
          render () {
            return (
              <div className="comment-box">
                  <CommentForm addComment={this._addComment.bind(this)} />
                    // Using the newly created CommentForm component
              </div>
            );
          }
      
          _addComment(author, body) {
            const comment = {
              id: this.state.comments.length + 1,
              author,
              body
            };
      
            // New array references help React stay fast.
            // So concat works better than push here.
            this.setState({ comments: this.state.comments.concat([comment]) });
            // Updates state when function is called by adding new comment
          }
      
          _getComments() {
      
                    // Reading from comment's state
            return this.state.comments.map(( comment) => {
              return (
                <Comment author={comment.author} body={comment.body} key={comment.id} />
            );
          });
        }
      }
      
  • Using Lifecycle Methods to Load Comments & Talking remote server

    First all one, is important understand React’s Lifecycle Methods:

    Lifecycle methods in React are functions that get called while the component is rendered for the first time or about to be removed from the DOM.

    • constructor()
    • componentWillMount() method is called before the component is rendered to the page.
    • render()
    • componentDidMount() is called after the component is rendered.
    • componentWillUnmount() is called immediately before the component is removed from the DOM.

    Note: In React, mounting means rendering for the first time.
    More info in facebook docs

  • Load data component with fetch data

    To load data, use fetch and this method is call in componentWillMount() method before render().

      class CommentBox extends React.Component {
        constructor() {
          super();
          this.state = {
            showComments: false,
            comments: [] // Initialed to an empty array
          };
        }
        // call fetch comments in componentWillMount Lifecycle
        componentWillMount() {
          this._fetchComments();
        }
        // fetch comment
        async _fetchComments() {
          try {
            let response = await fetch('comments.json');
            let comments = await response.json();
            this.setState({ comments })
          } catch(error) {
            console.log(error);
          }
        }
    
      }
    
    • Getting Periodic Updates

      In order to check whether new comments are added, we can periodically check the server for updates. This is known as polling.

      class CommentBox extends React.Component {
        ...
        componentDidMount() {
          setInterval(() => this._fetchComments(), 5000);
        }
      }
      

      React optimizes the rendering process by only updating the DOM when changes are detected on the resulting markup.

      • New state value after inital request –> DOM change happens
      • No new state value after second periodic Ajax request –> No DOM change
      • New state value after third periodic Ajax request –> DOM change happens
    • Memory Leaks on Page Change

      Page changes in a single-page app environment will cause each CommentBox component to keep loading new comments every five seconds, even when they are no longer displayed.

      • Preventing Memory Leaks
        Each component is responsible for removing any timers it has created. We will remove the timer on the componentWillUnmount method.
        class CommentBox extends React.Component {
          ...
          componentDidMount() {
            // Store timer as object property
            this._timer = setInterval(
              () => this._fetchComments(),
              5000
            );
          }
          // Run when component is about to be removed from the DOM
          componentWillUnmount() {
            clearInterval(this._timer);
          }
          ...
        }
        
        Reviewing the steps for loading Comments
        1. componentWillUnmount is called.
        2. render() is called and CommentBox is mounted.
        3. Component waits for API response and when it is received, setState() is called, causing render() to be called again.
        4. componentDidMount is called, causing this _fetchComments to be triggered
      • Routes

        React not including routing, is necessary routes dependencies, for example react-router and react-router-dom.

      In this example use this versions:

      • “react”: “^15.6.1”,
      • “react-dom”: “^15.6.1”,
      • “react-router”: “^4.1.1”,
      • “react-router-dom”: “^4.1.1”

      This example is other project:

      The scaffolding:

      project
      │
      └───public
      │   │   favicon.ico
      │   │   index.html
      │   │   manifest.json
      └───src
      │   │__home
      |   |   |_home.js
      |   |
      │   │__login
      |   |   |_login.js
      |   |
      │   │__register
      |       |_register.js
      |
      |__App.js
      |
      |__index.js
      

      In index.js import react-dom and use BrowserRouter to route the component App:

      import React from 'react';
      import { BrowserRouter } from 'react-router-dom'
      import ReactDOM from 'react-dom';
      import App from './App';
      
      ReactDOM.render((
        <BrowserRouter>
          <App />
        </BrowserRouter>
      ), document.getElementById('root'));
      

      The componnet App.js have other componnet to routing:

      import React from 'react';
      import { Route, Switch, Link } from 'react-router-dom'
      
      import './App.css';
      
      import Home from './home/home';
      import Login from './login/login';
      import Register from './register/register';
      
      const Main = () => (
        <main>
          <Switch>
            <Route exact path='/' component={Home}/>
            <Route path='/login' component={Login}/>
            <Route path='/register' component={Register}/>
          </Switch>
        </main>
      )
      
      // The Header creates links that can be used to navigate
      // between routes.
      const Header = () => (
        <header>
          <nav>
            <ul className="navigation">
              <li><Link to='/'>Home</Link></li>
              <li><Link to='/login'>Login</Link></li>
              <li><Link to='/register'>Register</Link></li>
            </ul>
          </nav>
        </header>
      )
      
      // Componet App to routing
      class App extends React.Component {
        render() {
          return (
            <div>
              <Header />
              <Main />
            </div>
            )
        }
      }
      
      export default App;
      

And it is all, any question please write me ;)

Angular router

El siguiente post es continuación del resumen de Angular 2

Hay varias formas de hacer un router en angular, una de ellas es la siguiente utilizando:

Para el ejemplo partimos de :

  • Un componente cualqiera como puede ser login situdado en /login/login.component el cual exportamos:

    import { Component, NgZone } from '@angular/core';
    
    @Component({
        selector: 'my-login',
        templateUrl: 'login.component.html',
        styleUrls: ['login.component.scss'],
    
    })
    export class LoginComponent {
      constructor() {}
    }
    
  • Creamos un modulo app-routing app-routing.module.ts, el cual importa:

    • Los componentes que vamos a routear
    • NgModule
    • Routes y RouterModule
    import { NgModule } from '@angular/core';
    import { Routes, RouterModule } from '@angular/router';
    import { LoginComponent } from './login/login.component';
    

    En el modulo creamos un array de rutas del objeto Routes en el cual se indica el path y el componente a dicho path:

      export const routes: Routes = [
        { path: 'login', component: LoginComponent },
        { path: 'register', component: RegisterComponent }
      ];
    

    En @NgModule se importan las rutas para el routerModule y se exportan una vez añadidas las rutas:

      @NgModule({
        imports: [ RouterModule.forRoot(routes) ],
        exports: [ RouterModule ],
      })
    

Por último exportamos AppRoutingModule y además todos los componentes los cuales serán incluidos en AppModule para ser declarados, de esta forma no tenemos que importar uno a uno en AppModule, si no todos los componentes añadidos en el array de AppRoutingModule.

export class AppRoutingModule {}
export const routedComponents = [ LoginComponent, RegisterComponent ];

En definitiva AppRoutingModule sería por ejemplo:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { LoginComponent } from './login/login.component';

export const routes: Routes = [
  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegisterComponent },
];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ],

})

export class AppRoutingModule {}

export const routedComponents = [ LoginComponent, RegisterComponent ];

Y en app.module se importa import { AppRoutingModule, routedComponents } from './app-routing.module'; para añadir a imports AppRoutingModule y declarar en declarations routedComponents.

app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule }  from '@angular/platform-browser';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { AppRoutingModule, routedComponents } from './app-routing.module';
import { AuthModule } from './shared/auth.module';


@NgModule({
    imports: [
        BrowserModule,
        AppRoutingModule, // Important add AppRoutingModule
        HttpModule
    ],
    declarations: [
        AppComponent,
        routedComponents // All components in AppRoutingModule
    ],
    bootstrap: [AppComponent]
})

export class AppModule { }

HTTP angular

El siguiente post es continuación del resumen de Angular 2

En lo posts anteriores:

Cargábamos los datos localmente desde fichero.

Con el servicio http de angular obtendremos los datos a través internet.

Con HTTP podemos hacer peticiones GET, POST, PUT, DELETE las cuales las podemos hacer de dos formas distintas:

  • Mediante observables, como por ejemplo el método login:
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';


@Injectable()
export class AuthService {
    private backendUrl = process.env.BACKEND_URI;


    constructor(private http: Http) { }


    login(credentials: Credentials) {
      // console.log('cre', credentials);
        this.http.post(this.backendUrl + '/login', credentials)
            .map((res) => res.json())
            .subscribe(
            // We're assuming the response will be an object
            // with the JWT on an id_token key
            (data) => localStorage.setItem('jwtToken', data.jwtToken),
            (error) => console.log(error)
            );
    }

Como se observa importamos la librería @angular/http y la instanciamos en el constructor.
Tambíen necesitamos importar rxjs/add/operator/map para map en el observable.

  • Con Promesas
getHeroes() {
   this.heroService.getHeroes()
                    .subscribe(
                      heroes => this.heroes = heroes,
                      error =>  this.errorMessage = <any>error);
 }

Se ha de tener en cuenta que en nuestro modulo tenemos que añadir http como provider en ambos casos.

Para más info Http client angular

Servicios

El siguiente post es continuación del resumen de Angular 2

En el post anterior Modelo de datos y mocks cargábamos datos mocks importando directamente el archivo, esta no es la mejor forma debido a:

  • Necesitamos importar el archivo en cualquier archivo que necesite acceso a los datos.
  • No es sencillo cambiar el flujo de trabajo entre los datos reales y los mockeados.
  • La carga de datos la realizan mejor las clases de services.
Los servicios son utilizados para organizar y compartir código a través de toda la app, suelen organizarse:

example.component.ts (Pide datos al servicio) ->
example.service.ts (accede a los datos para pasarselos al componente) -> mocks.ts

Como por ejemplo:

  • example.service.ts
    import { CARPARTS } from './mocks';
    export class RacingDataService {
      getCarParts() {
        return CARPARTS;
      }
    }
    
  • example.component.ts

    import { RacingDataService } from './racing-data.service';
    ...
    export class CarPartsComponent {
    carParts: CarPart[];
    
    ngOnInit() {
      let racingDataService = new RacingDataService();
      this.carParts = racingDataService.getCarParts();
      }
    }
    

    De esta formar tenemos los datos desacoplados, no tenemos que importar los datos cuando nos sea necesario, solo el servicio y este es el que nos devuelve los datos, de esta forma si tenemos que cambiar la fuente de datos solo lo cambiamos en un solo lugar.

Los servicios en Angular 2 pueden y es conveniente usar el patrón de inyección de dependencias

El inyector de dependencias se encarga de crear y enviar los datos que le pidamos:

Sabe si es necesario instanciar los datos para enviarlos o enviar los ya instanciados.

Los pasos para hacer inyectable a un servicio son los siguientes:

  1. Añadir el decorator @inyectable al servicio.
  2. Indicar nuestro servicio inyectable en providers de @NgModule.
  3. Inyectar la dependencía en el componente que sea necesario.
  4. Utilizar el servicio en el componente en ngOnInit().

Por ejemplo:

  • 1.Añadir el decorator @inyectable al servicio.
import { CARPARTS } from './mocks';
import { Injectable } from '@angular/core';

@Injectable()
export class RacingDataService {
  getCarParts() {
    return CARPARTS;
  }
}
  • 2.Indicar nuestro servicio inyectable en providers de @NgModule.

    ...
    import { RacingDataService } from './racing-data.service';
    
    @NgModule({
     declarations: [ AppComponent ],
     imports: [ BrowserModule, FormsModule ]
     bootstrap: [ AppComponent ] ,
     // En providers indicamos todos nuestros servicios inyectables
     providers: [ RacingDataService ]
    })
    class AppModule { }
    ...
    
  • 3y4 Inyectar la dependencía en el componente que sea necesario y utilizar el servicio en el componente en ngOnInit().

    ...
    import { RacingDataService } from './racing-data.service';
    
    @Component({ ... })
    export class CarPartsComponent {
    
    carParts: CarPart[];
    
    // Inyectar la dependencia en el componente
    constructor(private racingDataService: RacingDataService) { }
    
    // Utilizarla
    ngOnInit() {
      this.carParts = this.racingDataService.getCarParts();
    }
    }
    

De esta forma conseguimos que nuestro servicio:

  • Sea desacoplado
  • Escalable porque nuestras dependencias están ligadas a las clases
  • Testeable porque es sencillo mockear

Two-way Binding

El siguiente post es continuación del resumen de Angular 2

En los posts anteriores hemos visto:

JavaScript to HMTL

HTML to JavaScript

Two-way Binding es la unión de ambos para tener una comunicación bidireccional, es posible hacerlo de dos formas:

  • Utilizando los dos Bindings:

    En este ejemplo en el mismo input se muestra la cantidad (Binding de propiedades) y se añade la cantidad (Binding de eventos):

<input class="number" type="text" [value]="carPart.quantity" (input)="carPart.quantity = $event.target.value">
  • Utilizando la síntasis [ () ] (Banana in the box)

Para ello en la clase del componente se importa @angular/forms:

...
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [ AppComponent ],
  imports: [ BrowserModule , FormsModule ],
  bootstrap: [ AppComponent ],
  providers: [ RacingDataService ],
})
class AppModule { }
...

Y en el input se utiliza la síntasis [ () ]:

<input class="number" type="text" [(ngModel)]="carPart.quantity" >

De esta forma es mucho más clara y precisa.

Event Binding - Binding de eventos (One-Way Binding)

El siguiente post es continuación del resumen de Angular 2

En el post anterior se explicaba el (Binding de propiedades) el cual consistía en la comunicación de las propiedades de las clases de los componentes (TypeScript o JavaScript) al DOM, es decir:

JavaScript to HMTL

En el caso de Event Binding, es lo contrario:

HTML to JavaScript

Por ejemplo añadimos una función en nuestro componente:

export class CarPartsComponent {
  ...
  upQuantity() {
    alert("You Called upQuantity");
  }
  ...

Y este es llamado desde HTML, por ejemplo al hacer click:

  <button (click)="upQuantity( carPart )" >Click to alert</button>

Además del click tenemos los siguientes eventos:

<div (mouseover)="call()">

<input (blur)="call()">

<input (focus)="call()">

<input type="text" (keydown)="call()">

<form (submit)="call()">

Como es de esperar es posible coger información desde el elemento HTML para luego utilizarla en nuestra clase JS, por ejemplo vamos a mostrar un alert de cada letra que el usuario introduce en un input:

  • Código HTML:
<input type="text" (keydown)="showKey($event)">
  • TypeScript o JavaScript
export class CarPartsComponent {
  ...
  showKey(event) {
    alert(event.keyCode);
  }

  ...

En el siguiente post tratara de Two-way Binging, es decir comuncación bidireccional entre el DOM y Js.

Property Binding - Binding de propiedades y clases CSS (One-way binding)

El siguiente post es continuación del resumen de Angular 2

El Binding de propiedades significa mostrar las propiedades de nuesto componente en el DOM de la web y que cambie dinamícamente según cambía la propiedad, One-way binding es debido a que la comunicación es desde los modelos de los componentes de nuestra app al DOM no del DOM a la aplicación.

Con [ ] decimos a Angular 2 que esa propiedad del DOM va unida a una propiedad de nuestro modelo como por ejemplo:

  • <img [ src ] =" carPart.image ">
  • <div [ hidden ] ="!user.isAdmin" >secret</div>
  • <button [ disabled ] ="isDisabled" >Purchase</button>
  • <img [ alt ] ="image.description">

Binding Class (CSS)

También es posible hacer binding de una clase CSS dependiendo del modelo.

Por ejemplo la clase CSS

.featured {
  background: #57595D;
}

Es posible añadirla dependiendo del modelo, en este caso de ejemplo cardPart.featured devuelve true o false y si es true se añade la clase .featured al elemento, está es la única síntasis posible:

<div [class.featured]="carPart.featured" >

Hay que tener en cuenta, que de esta forma cada elemento tiene su scope, el código generado sería el siguiente:

<div _ngcontent-opf-2 >

.featured[_ngcontent-opf-2] {
  background: #57595D;
}

En definitiva:

  • El binding de propiedades permite hacer binding entre las propiedades del componente y el DOM.
  • Cualquier actualización del valor de la propiedad actualizara el DOM, pero no viceversa, una actualización del DOM no actualiza el modelo (One-way binding).
  • El binding de clases CSS nos permite especificar estilos a un elemento del DOM si la propiedad del componente es true, tienen su propio scope del estilo que es dado.

Modelos y uso de mocks

El siguiente post es continuación del resumen de Angular 2

Modelos en angular 2

Básicamente los modelos en angular 2 son clases como por ejemplo:

export class Carpart {
  id: number;
  name: string;
  description: string;
  inStock: number;
  price: number;
}

De esta forma en la clase de nuestro componente podemos crear arrays de la clase Cardpart, importando la clase.

import { Component } from '@angular/core';
import { CarPart } from './car-part';

export class CarPartsComponent {
  carParts: CarPart[] = [{
    "id": 1,
    "name": "Super Tires",
    "description": "These tires are the very best",
    "inStock": 5,
    "price": 4.99
}, { ... }, { ... }]
...

Uso de mocks en angular 2

Una de las formas posibles para comenzar a desarrollar nuestra aplicación sin disponer aún los datos que nos va a suministrar la API es mediante Mocking (mockear datos).
Una forma simple es creando nuestro array de datos JSON o de clases que vayamos a utilizar y asignarlo a las propiedades de los componentes que nos sea necesario.

Como por ejemplo:

import { CarPart } from './car-part';

export const CARPARTS: CarPart[] = [{
  "id": 1,
  "name": "Super Tires",
  "description": "These tires are the very best",
  "inStock": 5,
  "price": 4.99
  }, { ... }, { ... }];

Y ahora en nuestro componente mediante la función ngOnInit() damos el valor a la propiedad correspondiente, en este ejemplo a la propiedad cardParts se le asigna el valor CARDPARTS el cual es el array de cardparts que hemos importado.

import { Component } from '@angular/core';
import { CarPart } from './car-part';
import { CARPARTS } from './mocks';
...
})

export class CarPartsComponent {
  carParts: CarPart[] ;

  ngOnInit() {
    this.carParts = CARPARTS;
  }
...

De esta forma podemos comenzar a desarrollar nuestra app con datos de prueba mocks ;).

Organización de código

El siguiente post es continuación del resumen de Angular 2

Organización de los componentes en Angular 2

Como vulgarmente se dice:

divide o vencéras

Partiendo del siguiente ejemplo en el que tenemos AppComponent en app/main.ts:

import { NgModule, Component } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

@Component({
  selector: 'my-app',
  template: `<h1> {{title}} </h1>
    <h2>{{carPart.name}}<h2>
    <p>{{carPart.description}}<p>
    <p>{{carPart.inStock}} in Stock<p>`
})

class AppComponent {
    title = 'Ultra Racing';
    carPart = {
        "id": 1,
        "name": "Super Tires",
        "description": "These tires are the very best",
        "inStock": 5
        };
  }


@NgModule ({
  declarations: [ AppComponent ]
})

class AppModule { }

platformBrowserDynamic()
  .bootstrapModule(AppModule);

Movemos toda la parte del componente AppComponent a un fichero aparte como por ejemplo app.component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<h1>{{title}}</h1>`
})

// Importante, exportar para utilizar el componente
export class AppComponent {
  title = 'Ultra Racing';
  carParts = [...];
  totalCarParts() { ... };
}

Es importante, exportar para utilizar el componente export class..

En conclusión ahora disponeos de dos archivos:

  • main.ts Que importa el componente:
// Importante hacer el import
import { AppComponent } from './app.component';

@NgModule({
  declarations: [ AppComponent ],
  imports: [ BrowserModule ],
  bootstrap: [ AppComponent ]
})
class AppModule { }
  • Y el propio componente en app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<h1>{{title}}</h1>`
})

export class AppComponent {
  title = 'Ultra Racing';
  carParts = [...];
  totalCarParts() { ... };
}
Mover el código HTML CSS

Ahora procedemos a separar el código del template (html) y añadir los estilos,

Como por ejemplo en el componente anterior:

import { Component } from '@angular/core';

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

export class AppComponent {
  title = 'Ultra Racing';
  carParts = [...];
  totalCarParts() { ... };
}

Como podemos observar el código HTML se encuentra en un archivo aparte app.component.html :

<p>There is a example ;).</p>
<ul>...</ul>

y el css en otro app.component.css :

.description {
  color: #444;
  font-size: small;
}
.price {
  font-weight: bold;
}

De esta forma, nuestro componente se encuentra dividido en tres partes cada una en un archivo:

  • La lógica del componente en app.component.ts el cual se exporta para incluirlo en @module en main.ts.
  • El template con el html en app. component.html
  • Estilos del componente en app.component.css

Angular 2 - Estructura de directivas, Pipes y Métodos

Directivas

El siguiente post es continuación del resumen de Angular 2

Una directiva de Angular es la forma de añadir comportamiento dinámico a HTML mediante la etiqueta o selector que creamos.

Existen tres tipos diferentes de directivas:

Podemos verlas en el fragmento de código:

...
@Component({
  // El selector y templatte sería el primer tipo de directiva
  selector: 'my-app',
  template: `<h1>{{title}}</h1>
    <ul>
      <li *ngFor="let carPart of carParts">
        <h2>{{carPart.name}}<h2>
        <p>{{carPart.description}}<p>
        <p *ngIf="carPart.inStock > 0">{{carPart.inStock}} in Stock</p>
        <p *ngIf="carPart.inStock === 0">Out of Stock</p>
      </li>
    </ul>`

  // En el propio template observamos las directivas de estructura *ngFor y *ngIf

})
class AppComponent {
...

Pipes y Métodos

Un pipe coge un dato de entrada y lo transforma a la salida deseada, como por ejemplo:

Métodos (Methods) como podemos imaginar es añadir métodos en la clase de nuestro componente para luego ser utilizada:

...
@Component({
  selector: 'my-app',
  template: `<h1>{{title}}</h1>`

  })

class AppComponent {
  exampleMethod() {
      return 10;
    }
}