viernes, 19 de mayo de 2017

Angular 2 y C3.css (3): Definición de componentes visuales primarios

Introducción

Queremos crear 3 componentes:

1. Componente principal AppComponent que es el contenedor de todo con el boton "hamberger" que oculta y muestra el menu lateral
2. Menu Lateral Izquierdo (Sidebar): SidebarComponent
3. Caja de contenidos en la parte derecha:ContentComponent

1. AppComponent

Veamos el código type script (app.component.ts)

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

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

export class AppComponent {
  title = 'app works!';
  sbVisible = false; // whether sidebar menu is visible or not

  // Hide or show sidebar
  hideSBOnOff(): void {
    this.sbVisible = !this.sbVisible;
  }
}

De este código destacamos:

1. La variable sbVisible que es la que indoca si el menú de la barra lateral esta visible (display:in-line) o si está oculto (display:none).

2. La función hideSBOnOff() lo que hace es cambiar el valor de sbVisible



Vemos el código html (app.component.html)

<div class="w3-main" id="main">

  <div class="w3-row w3-teal w3-border" id ="main-row">
    <div class="w3-container w3-col" style="width:100px">
      <button class="w3-button w3-xxlarge" (click)="hideSBOnOff()">&#9776;</button>
    </div>
    <div class="w3-container w3-rest">
      <h1>My Application</h1> 
    </div>
  </div><!--  end main-row-->
  

  <!--  Left for sidebar -->
  <app-sidebar [visible]="sbVisible"></app-sidebar>

  <!--  Right for content -->
  <app-content [sBarVisible]="sbVisible"></app-content>

</div> <!-- end main -->

De este código destacamos:

1. La creación de caracter "hamberguer" con &#9776;

2. Como llamamos a la función hideSBOnOff() al hacer click del boton: (click)="hideSBOnOff()"

3. Como insertamos los componentes AppSidebar y AppContent con las directivas <app-sidebar> y <app-content>

4. Como pasamos la variable sbVisible a cada componente, dentro de sus directivas correspondientes. Para ello, cada componente debe tener un atributo con la anotacion @Input que para el AppSidebar será el atributo "visible" y para el AppContent será "sBarVisible". Los atributos de cada componente iran entre corchetes [].

2. SidebarComponent

El código typescript es (sidebar.component.ts)

import { Component, OnInit, Input } from '@angular/core';

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

export class SidebarComponent implements OnInit {
  // whether is visible or not this component
  @Input() visible: boolean; // receives input from parent

  constructor() { }

  ngOnInit() {
  }

 // Gets the style and show or hide this sidebar
 getSideBarStyle() {
    const SideBarStyle = {
       'width': '25%',
       'display': this.visible ? 'inline-block' : 'none',
    };
    return SideBarStyle;
  }
}

Destacamos:

1. selector: 'app-sidebar' que es la directiva que utiliza el componente padre (appComponent) para incrustar este componente dentro del html del componente padre.

2. @Input() visible que es el atributo que le pasa el componente padre para que esté visible o no.

3. getSideBarStyle(): Que es la función que nos devuelve el estilo en función de si es visible o no. También nos da la anchura.

Veamos el codigo html (sidebar.component.html)

<div class="w3-sidebar w3-bar-block w3-card-2 w3-animate-left"  [ngStyle]="getSideBarStyle()" id="mySidebar">
  <!-- button class="w3-bar-item w3-button w3-large" (click)="hideOnOff()">Close &times;</button -->
  <a href="#" class="w3-bar-item w3-button">Link 1</a>
  <a href="#" class="w3-bar-item w3-button">Link 2</a>
  <a href="#" class="w3-bar-item w3-button">Link 3</a>

</div>


Destacamos como con la notación [ngStyle]="getSideBarStyle()" le asignamos el valor del estilo para que sea visible (display:in-line) o no (display:none).



3. ContentComponent

Veamos el código typescript:

import { Component, OnInit, Input, Output } from '@angular/core';

@Component({
  selector: 'app-content',
  templateUrl: './content.component.html',
  styleUrls: ['./content.component.css']
})
export class ContentComponent implements OnInit {
  @Input() sBarVisible: boolean; // <-- added Input annotation

  constructor() {
    this.sBarVisibleEmitter = new EventEmitter();
  }

  ngOnInit() {
  }

  // gets this componet style
  getContentStyle() {
    const mainStyle = {
       'margin-left': this.sBarVisible ? '25%' : '0%',
    };
    return mainStyle;
  }
}


Destacar:
1. selector: 'app-content' que es la directiva que usa el componente padre en el html para incluirlo
2. @Input sBarVisible que es la variable que le pasa el componente padre para decirle que la barra lateral esta visible o no para que este componente se readapte
3. getContentStyle() que es la función que cambia el estilo para que se comparta el contenido total con el menu lateral. Es este caso cuando la barra lateral es visible le damos un margen izquierdo del 25%

Veamos el html (content.component.html)

<div class="w3-tile" [ngStyle]="getContentStyle()" id="content">

  <img src="../assets/images/img_car.jpg" alt="Car" style="width:100%">

  <div class="w3-container">
    <p>In this example, the sidebar is hidden (style="display:none")</p>
    <p>It is shown when you click on the menu icon in the top left corner.</p>
    <p>When it is opened, it shifts the page content to the right.</p>
    <p>We use JavaScript to add a 25% left margin to the div element with id="main" when this happens. The value "25%" matches the width of the sidebar.</p>
  </div>

</div>

A destacar:

1. La aplicación de estilos con la directiva ngStyle: [ngStyle]="getContentStyle()" que utiliza la función getContentStyle del componente.

2. El resto de contenido es copiado de la web de w3schools. Observar que la foto del coche se ha puesto en el directorio assets/images

Pero no debemos olvidar el app.module.ts que es el que nos une todos los componentes:

3. AppModule.ts

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

import { AppComponent } from './app.component';
import { SidebarComponent } from './my_ui/sidebar/sidebar.component';
import { ContentComponent } from './my_ui/content/content.component';

@NgModule({
  declarations: [
    AppComponent,
    SidebarComponent,
    ContentComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Observar que cada componente lo crea en una carpeta nueva. Y también he creado la carpeta my_ui para saber tener todo junto esta parte de interfaz de usuario (my_ui)

Si ejecutamos queda esto:

Y si mostramos el menu lateral dandole al boton hamberguer:




4. Conclusiones

De momento no hemos utilizado el modelado de datos. En esta tercera entrega solo hemos comprobado que los componentes hacen lo que queremos.

Angular 2 y C3.css (2): Definición del modelo de datos

Introducción

Primeramente vamos a definir el modelado de los elementos de la interfaz de usuario

1. Modelo de datos

En principio crearemos varios ficheros: 
  • config.model.ts: donde guardaremos parámetros y enumeraciones
  • menu.model.ts: que define la estructura de menú
Veamos el primero (config.model.ts):

/**
 * Configuration and base enums
 */

/**
 * Type of action in a menu
 */
export enum MenuAction {
    Menu = 0,    // Link to submenu
    Component,   // Link to a component
    Procedure,   // Link to a procedure
    URL          // link to an URL
}


Y ahora el segundo (menu.model.ts)

/**
 * Menu structure
 */
import { MenuAction } from './config.model'; // <-- import this

export class Menu {
  title: string;            // title of the menu
  actionType: MenuAction;   // Type of action as MenuAction
  action: string;           // action
  submenu: Menu;            // submenu
  info: string;             // Additional info

  constructor(title: string, actionType: MenuAction,
              info: string, action: string, submenu: Menu) {
  this.title = title;
  this.actionType = actionType;
  this.info = info;
  this.action = action ;
  this.submenu = submenu;
  }
}





jueves, 18 de mayo de 2017

Angular 2 y C3.css (1): Perspectiva inicial

1. Introducción


Vamos a crear una pequeña aplicación con Angular 2 y C3.css

La decisión de usar C3,css es:
  1. No tiene javascript, por tanto no deberíamos tener problemas con Angular2
  2. Es muy potente
  3. Es muy pequeña
  4. Y sobre todo porque es "responsive" y "mobile first"
Yo estoy utilizando Eclipse con Webclipse.

2. Creación del proyecto

Veamos los pasos que he hecho:

1. He creado un proyecto Angular 2
2. He descargado C3.css a la carpeta app/assets
3. En src/styles.css he puesto la ruta a C3.css


@import './assets/w3.css';

3. Diseño de la interfaz de usuario

Queremos tener un diseño parecido a este de W3Schools . No quiero redescubrir la rueda y utilizar recursos libres que parece que estan funcionando bien.



Para ello adaptamos a este diseño

+-------------------------------------------------+
| ☰              TITULO                          |
+------------+------------------------------------+
|            |                                    | 
| MENU       | ZONA DE CONTENIDO                  | 
| LATERAL    |                                    | 
| OCULTABLE  |                                    | 
|            |                                    | 
|            |                                    | 
+------------+------------------------------------+


Como vemos, queremos un panel lateral que se puede ocultar y mostrar que va a ser nuestro menú, y un panel de contenidos.

Ahora nos queda adaptar lo que nos da W3 al modo de actuar de Angular 2.

Para ello definiremos los siguientes elementos

1. Estructura de datos que guarde el menú (tipo árbol)
2. Componente del menú lateral (sidebar)
3. Componente del contenido principal
4. Servicio simple que proporcione la estructura de datos del menú lateral

De momento, para esta introducción ya tenemos demasiado. Mas adelante lo podemos complicar añadiendo mas components, barras de estado etc.

4. Estructura de datos del menú

Crearemos 2 ficheros 
  • config.model.ts: donde guardaremos parámetros y enumeraciones
  • menu.model.ts: que define la estructura de menú
Veamos el primero:

/**
 * Configuration and base enums
 */

/**
 * Type of action in a menu
 */
export enum MenuAction {
    Menu = 0,    // Link to submenu
    Component,   // Link to a component
    Procedure,   // Link to a procedure
    URL          // link to an URL
}


Y ahora el segundo

/**
 * Menu structure
 */
import { MenuAction } from './config.model'; // <-- import this

export class Menu {
  title: string;            // title of the menu
  actionType: MenuAction;   // Type of action as MenuAction
  action: string;           // action
  submenu: Menu;            // submenu
  info: string;             // Additional info

  constructor(title: string, actionType: MenuAction,
              info: string, action: string, submenu: Menu) {
  this.title = title;
  this.actionType = actionType;
  this.info = info;
  this.action = action ;
  this.submenu = submenu;
  }
}