Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Angular 2: Getting Started

Angular 2: Getting Started

Angular 2 for beginners, including app architecture, components, services, http and routing. Everything you need to build a much-more-than-basic app. Presented at SheCodes(tlv), May 2016.

Shmuela Jacobs

May 31, 2016
Tweet

More Decks by Shmuela Jacobs

Other Decks in Programming

Transcript

  1. Shmuela Jacobs - ng-ninja by day - Octo-Kitten by evening

    - vegan Goblin by night Sr. Web Developer @ 500Tech
  2. • Intro to Angular 2 • TypeScript • App architecture

    • Components • Built-in Directives • Services • Http • Routing
  3. JavaScript + Types TypeScript ES6 (ES-2015) JavaScript (ES5) • type

    checking
 string, number, boolean, any, Array<T> • custom types - interfaces • code help - intellisense • decorators • and more... Typescript: Angular 2's Secret Weapon - Dan Wahlin ng-conf 2016: https://youtu.be/e3djIqAGqZo
  4. 
 
 
 
 class Dog { age = 0;


    children = [];
 
 talk(times: number) {
 const bark = 'Ruff! ';
 return bark.repeat(times);
 }
 }
 
 let Ziggi = new Dog();
 console.log(Ziggi.talk(3)); TypeScript + tooling
  5. interface Animal {
 age: number,
 children: Array<Animal>,
 talk(times: number): string


    } class Dog implements Animal { age = 0;
 children = [];
 
 talk(times: number) {
 const bark = 'Ruff! ';
 return bark.repeat(times);
 }
 }
 
 let Ziggi = new Dog();
 console.log(Ziggi.talk(3)); TypeScript + tooling
  6. E-Store search 4 <header>
 <a href="home.html">E-Store</a>
 </header>
 <aside>
 <a href="cart.html">


    4 <img src="cart.jpg">
 </a>
 </aside>
 <main>
 <div>
 <input type="text">
 <button>search</button>
 </div>
 <div id="products">
 <ul>
 <li>
 <a href="product1.html">
 <h3>Product Title</h3>
 <img src="product.jpg">
 </a>
 </li> <li>...</li>
 </ul>
 </div>
 </main> appRoot my-store header search-bar products-list nav-bar product product product product x
  7. appRoot my-store header search-bar products-list nav-bar product product product product

    x Component tree <product [product]="productToDisplay" (addToCart)="addProductToCart($event)"> </product> ( output ) [ input ]
  8. appRoot my-store header search-bar products-list nav-bar product product product product

    x Change Detection product name changed using OnPush change detection strategy
  9. Component Template </> Controller { } Style {CSS} Hi She

    Codes! <h1> Hi {{name}}! </h1> name = 'She Codes'; h1 { color: red }
  10. Component Template </> Controller { } Directive { } Component

    </> + { } Service { } Style {CSS} Hi She Codes! <h1> Hi {{name}}! </h1> name = 'She Codes'; h1 { color: red }
  11. Break Angular 2 Project Setup With Angular CLI Shmuela Jacobs

    [email protected] linkedin.com/in/shmuelaj github.com/shmool @ShmuelaJ
  12. Bootstrapping the root component // main.ts import { bootstrap }

    from '@angular/platform-browser-dynamic';
 import { MyStoreComponent } from './app/';
 
 bootstrap(MyStoreComponent);
 // index.html <body> <my-store></my-store> <script src="vendor/es6-shim/es6-shim.js"></script>
 <script src="vendor/reflect-metadata/Reflect.js"></script>
 <script src="vendor/systemjs/dist/system.src.js"></script>
 <script src="vendor/zone.js/dist/zone.js"></script>
 
 <script>
 System.import('system-config.js').then(function () {
 System.import('main');
 }).catch(console.error.bind(console));
 </script> </body>
  13. Module Component Template </> Controller { } Directive { }

    Component </> + { } Service { } Style {CSS}
  14. Bootstrapping the root component // main.ts import { bootstrap }

    from '@angular/platform-browser-dynamic';
 import { MyStoreComponent } from './app/';
 
 bootstrap(MyStoreComponent);
 // index.html <body> <my-store></my-store> <script src="vendor/es6-shim/es6-shim.js"></script>
 <script src="vendor/reflect-metadata/Reflect.js"></script>
 <script src="vendor/systemjs/dist/system.src.js"></script>
 <script src="vendor/zone.js/dist/zone.js"></script>
 
 <script>
 System.import('system-config.js').then(function () {
 System.import('main');
 }).catch(console.error.bind(console));
 </script> </body>
  15. Bootstrapping the root component // main.ts import { bootstrap }

    from '@angular/platform-browser-dynamic';
 import { MyStoreComponent } from './app/';
 
 bootstrap(MyStoreComponent);
 // index.html <body> <my-store></my-store> <script src="vendor/es6-shim/es6-shim.js"></script>
 <script src="vendor/reflect-metadata/Reflect.js"></script>
 <script src="vendor/systemjs/dist/system.src.js"></script>
 <script src="vendor/zone.js/dist/zone.js"></script>
 
 <script>
 System.import('system-config.js').then(function () {
 System.import('main');
 }).catch(console.error.bind(console));
 </script> </body>
  16. Basic component import { Component } from '@angular/core';
 
 @Component({

    
 selector: 'my-store',
 templateUrl: './app/my-store.component.html', 
 }) 
 export class MyStoreComponent {}
 my-store
  17. Basic component import { Component } from '@angular/core'; 
 


    @Component({ moduleId: module.id,
 selector: 'my-store',
 templateUrl: 'my-store.component.html'
 }) 
 export class MyStoreComponent {}
 my-store
  18. Basic component import { Component } from '@angular/core'; 
 


    @Component({ moduleId: module.id,
 selector: 'my-store', template: '<h1>Welcome!</h1>' 
 }) 
 export class MyStoreComponent {}
 my-store
  19. Basic component import { Component } from '@angular/core'; 
 


    @Component({ moduleId: module.id,
 selector: 'my-store', template: '<h1>Welcome!</h1>', styleUrls: ['product.component.css']
 }) 
 export class MyStoreComponent {}
 my-store
  20. Using child component my-store import { Component } from '@angular/core';

    import { ProductComponent } from './product/product.component';
 
 @Component({ moduleId: module.id,
 selector: 'my-store', template: '<product></product>', directives: [ProductComponent]
 }) 
 export class MyStoreComponent {}

  21. Using child component import { Component } from '@angular/core'; import

    { ProductComponent } from './product;
 
 @Component({ moduleId: module.id,
 selector: 'my-store', template: '<product></product>', directives: [ProductComponent]
 }) 
 export class MyStoreComponent {}
 // product/index.ts - barrel export { ProductComponent } from './action.component'; my-store
  22. Basic component import { Component } from '@angular/core';
 
 @Component({

    
 selector: 'product',
 templateUrl: 'app/product/product.component.html'
 })
 export class ProductComponent {}
 // parent component template <product></product> product my-store // generate new component > ng g c product
  23. Basic component import { Component } from '@angular/core';
 
 @Component({


    moduleId: module.id,
 selector: 'product',
 templateUrl: 'product.component.html'
 })
 
 export class ProductComponent {}
 // parent component template <product></product> product my-store // generate new component > ng g c product
  24. Basic component import { Component } from '@angular/core';
 
 @Component({


    moduleId: module.id,
 selector: 'product',
 template: `
 <h1>Hello World!</h1>`
 })
 
 export class ProductComponent {}
 product // generate new component > ng g c product
  25. Binding to controller member import { Component } from '@angular/core';


    
 @Component({
 moduleId: module.id,
 selector: 'product',
 template: `
 <h1>{{ title }}</h1>`
 })
 
 export class ProductComponent { title = 'Hello World!'; }
 product // generate new component > ng g c product
  26. Binding to controller method import { Component } from '@angular/core';


    
 @Component({
 moduleId: module.id,
 selector: 'product',
 template: `
 <h1>{{ getTitle() }}</h1>`
 })
 
 export class ProductComponent { 
 getTitle() {
 return 'Hello World!';
 } }
 product // generate new component > ng g c product
  27. Class members and methods import { Component } from '@angular/core';


    
 @Component({
 moduleId: module.id,
 selector: 'product',
 template: `
 <h1>{{ getTitle() }}</h1>`
 })
 
 export class ProductComponent { title = 'Hello World!'; 
 getTitle() {
 return this.title;
 } getTitle2() {
 return this.getTitle();
 } }
 product
  28. Typings import { Component } from '@angular/core';
 
 @Component({
 moduleId:

    module.id,
 selector: 'product',
 template: `
 <h1>{{ getTitle() }}</h1>`
 })
 
 export class ProductComponent { title: string = 'Hello World!'; 
 getTitle(): string {
 return this.title;
 } }
 product
  29. Passing input import { Component } from '@angular/core';
 
 @Component({


    moduleId: module.id,
 selector: 'product',
 template: `
 <h1>{{ title }}</h1>`, inputs: ['title']
 })
 
 export class ProductComponent { title: string; }
 // parent component template 
 <product title="Hello World!"></product> product my-store [ input ]
  30. Binding input import { Component } from '@angular/core';
 
 @Component({


    moduleId: module.id,
 selector: 'product',
 template: `
 <h1>{{ title }}</h1>`, inputs: ['title']
 })
 
 export class ProductComponent { title: string; }
 // parent component template 
 <product [title]="productTitle"></product> 
 // parent component controller productTitle ='Hello World!'; product my-store [ input ]
  31. Binding input import { Component } from '@angular/core';
 
 @Component({


    moduleId: module.id,
 selector: 'product',
 template: `
 <h1>{{ product.title }}</h1>`, inputs: ['product']
 })
 
 export class ProductComponent { product: any; }
 // parent component template 
 <product [product]="productToDisplay"></product> 
 // parent component controller productToDisplay = { title: 'Hello World!' }; product my-store [ input ]
  32. Binding to element property import { Component } from '@angular/core';


    
 @Component({
 moduleId: module.id,
 selector: 'product',
 template: `
 <h1 [style.color]="product.color">{{ product.title }}</h1>`, inputs: ['product']
 })
 
 export class ProductComponent { product: any; }
 // parent component template 
 <product [product]="productToDisplay"></product> 
 // parent component controller productToDisplay = { title: 'Hello World!', color: 'red' }; product my-store [ input ]
  33. Catching events import { Component } from '@angular/core';
 
 @Component({


    moduleId: module.id,
 selector: 'product',
 template: `
 <h1 [style.color]="product.color">{{ product.title }}</h1>
 <button (click)="changeColor()">Change Color</button>`, inputs: ['product']
 })
 
 export class ProductComponent { product: any;
 
 changeColor() {
 this.product.color = 'blue'; } }
 // parent component template
 <product [product]="productToDisplay"></product> 
 // parent component controller productToDisplay = { title: 'Hello World!', color: 'red' }; product my-store ( output ) button
  34. Emitting events import { Component, EventEmitter } from '@angular/core';
 


    @Component({
 moduleId: module.id,
 selector: 'product',
 template: `
 <h1 [style.color]="product.color">{{ product.title }}</h1>
 <button (click)="changeColor('green')">Green</button> <button (click)="changeColor('blue')">Blue</button>`, inputs: ['product'], outputs: ['color']
 })
 
 export class ProductComponent { product: any; 
 color = new EventEmitter<string>();
 
 changeColor(chosenColor) {
 this.color.emit(chosenColor);
 } }
 product ( output ) my-store
  35. Catching custom events (parent) @Component({ ... selector: 'product',
 inputs: ['product'],

    outputs: ['color']
 })
 import { Component } from '@angular/core'; import { ProductComponent } from './product';
 
 @Component({ moduleId: module.id,
 selector: 'my-store', template: ` <product [product]="productToDisplay" (color)="changeProductColor($event)"> </product>`, directives: [ProductComponent]
 })
 export class MyStoreComponent { productToDisplay = { title: 'Hello World!', color: 'red' };
 
 changeProductColor(event) {
 this.productToDisplay.color = event;
 } } product ( output ) my-store
  36. More built-in directives ng-class [ngClass] ng-style [ngStyle] ng-switch *ngSwitch ng-switch-when

    *ngSwitchWhen ng-switch-default *ngSwitchDefault form form (QTOUCTGCYJQNG PQVJGTUWDLGEV
  37. constructor import { Component } from '@angular/core'; 
 
 


    @Component({
 moduleId: module.id,
 selector: 'product',
 templateUrl: 'product.component.html'
 })
 
 export class ProductComponent { constructor() {
 // do simple stuff
 } }

  38. constructor import { Component } from '@angular/core'; import { ProductService

    } from '../services/product.service';
 
 
 @Component({
 moduleId: module.id,
 selector: 'product',
 templateUrl: 'product.component.html'
 })
 
 export class ProductComponent { constructor(private productService: ProductService) {
 // do simple stuff
 } }
 The service needs to be provided
  39. onInit import { Component, OnInit } from '@angular/core'; import {

    ProductService } from '../services/product.service';
 
 
 @Component({
 moduleId: module.id,
 selector: 'product',
 templateUrl: 'product.component.html'
 })
 
 export class ProductComponent implements OnInit { constructor(private productService: ProductService) {
 // do simple stuff
 } ngOnInit() {
 // do elaborate stuff this.productDetails = this.productService.getDetails();
 } }

  40. More component lifecycle hooks // Pseudo Code import { Component,

    OnInit, ... } from '@angular/core'; 
 @Component({
 ... })
 
 export class ProductComponent implements OnInit { ngOnInit() ngOnChanges(changes) ngDoCheck() ngOnDestroy() ngAfterContentInit() ngAfterContentChecked() ngAfterViewInit() ngAfterViewChecked() }
  41. Service = class import { Injectable } from '@angular/core';
 


    @Injectable()
 export class ProductsService {
 
 constructor() {}
 
 }
 // generate new service > ng g s product
  42. Service = class import { Injectable } from '@angular/core';
 


    @Injectable()
 export class ProductsService { products = [
 { id: 1, title: 'Arduino' },
 { id: 2, title: 'Raspberry Pi' }
 ];
 
 constructor() {}
 
 getProducts() {
 return this.products;
 }
 
 addProduct(product) {
 this.products.push(product);
 }
 
 }
  43. Injecting the service ...
 export class ProductsService { getProducts() {


    return this.products;
 }
 } import { Component, OnInit } from '@angular/core';
 import { ProductsService } from './products.service';
 
 @Component({
 moduleId: module.id,
 selector: 'my-store',
 templateUrl: 'my-store.component.html'
 })
 export class MyStoreComponent implements OnInit { products: Array<any>; constructor(private productsService: ProductsService) {}
 
 ngOnInit() {
 this.products = this.productsService.getProducts();
 }
 } service component inject
  44. Providing the service - component level import { Component, OnInit

    } from '@angular/core';
 import { ProductsService } from './products.service';
 
 @Component({
 moduleId: module.id,
 selector: 'my-store',
 templateUrl: 'my-store.component.html', 
 providers: [ProductsService]
 }) 
 export class MyStoreComponent implements OnInit { products: Array<any>; constructor(private productsService: ProductsService) {}
 
 ngOnInit() {
 this.products = this.productsService.getProducts();
 }
 } service component provide
  45. Providing the service - app level // main.ts import {

    bootstrap } from '@angular/platform-browser-dynamic';
 import { MyStoreComponent } from './app/'; import { ProductsService } from './app/products.service';
 
 bootstrap(MyStoreComponent, [ProductsService]); service app provide
  46. Setting up Http // if angular/http is not installed yet

    > npm i @angular/http -S // main.ts import { HTTP_PROVIDERS } from '@angular/http'; bootstrap(MyStoreComponent, [HTTP_PROVIDERS]);
  47. Setting up Http // if angular/http is not installed yet

    > npm i @angular/http -S // main.ts import { HTTP_PROVIDERS } from '@angular/http'; bootstrap(MyStoreComponent, [HTTP_PROVIDERS]); // service import { Injectable } from '@angular/core';
 import { Http } from '@angular/http';
 import { Observable } from 'rxjs/Observable';
 import 'rxjs/add/operator/map'; @Injectable()
 export class ProductsService {
 
 constructor(private http: Http) {} }
  48. import { Injectable } from '@angular/core';
 import { Http }

    from '@angular/http';
 import { Observable } from 'rxjs/Observable';
 import 'rxjs/add/operator/map'; @Injectable()
 export class ProductsService {
 
 constructor(private http: Http) { 
 
 } getData(): Observable<any> {
 return this.http.get('https://myData.com/products')
 .map(response => {
 return response.json();
 });
 } } Http GET Rx Observables visualized: http://rxmarbles.com/
  49. import { Injectable } from '@angular/core';
 import { Http }

    from '@angular/http';
 import { Observable } from 'rxjs/Observable';
 import 'rxjs/add/operator/map'; @Injectable()
 export class ProductsService {
 
 constructor(private http: Http) { 
 
 } getData(): Observable<any> {
 return this.http.get('https://myData.com/products')
 .map(response => {
 return response.json();
 });
 } } Observables Rx Observables visualized: http://rxmarbles.com/
  50. import { Injectable } from '@angular/core';
 import { Http }

    from '@angular/http';
 import { Observable } from 'rxjs/Observable';
 import 'rxjs/add/operator/map'; @Injectable()
 export class ProductsService {
 
 constructor(private http: Http) { this.getData().subscribe( (data) => {
 this.products = data;
 }, (error) => { console.log(error); }); } getData(): Observable<any> {
 return this.http.get('https://myData.com/products')
 .map(response => {
 return response.json();
 });
 } } Subscribe() Rx Observables visualized: http://rxmarbles.com/
  51. import { Injectable } from '@angular/core';
 import { Http }

    from '@angular/http';
 import { Observable } from 'rxjs/Observable';
 import 'rxjs/add/operator/map'; @Injectable()
 export class ProductsService {
 
 constructor(private http: Http) { this.getData().subscribe( (data) => {
 this.products = data;
 }, (error) => { console.log(error); }); } getData(): Observable<any> {
 return this.http.get('https://myData.com/products')
 .map(response => {
 return response.json();
 });
 } } Subscribe() Rx Observables visualized: http://rxmarbles.com/
  52. Subscribe() import { Injectable } from '@angular/core';
 import { Http

    } from '@angular/http';
 import { Observable } from 'rxjs/Observable';
 import 'rxjs/add/operator/map'; @Injectable()
 export class ProductsService {
 
 constructor(private http: Http) { this.getData().subscribe( (data) => {
 this.products = data;
 }, (error) => { console.log(error); }); } getData(): Observable<any> {
 return this.http.get('https://myData.com/products')
 .map(response => {
 return response.json();
 });
 } } Rx Observables visualized: http://rxmarbles.com/
  53. Router Component my-store import { Component } from '@angular/core'; import

    { Routes, Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from '@angular/router'; 
 @Component({
 moduleId: module.id,
 selector: 'my-store',
 templateUrl: 'my-store.component.html', 
 directives: [ROUTER_DIRECTIVES],
 providers: [ROUTER_PROVIDERS]
 }) @Routes([
 
 ])
 export class MyStoreComponent { constructor(private router: Router) {} 
 } Make sure you have all this when using Angular CLI
  54. Router Component my-store import { Component } from '@angular/core'; import

    { Routes, Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from '@angular/router'; import { ProductListComponent } from './+product-list'; import { ProductComponent } from './+product'; 
 @Component({
 moduleId: module.id,
 selector: 'my-store',
 templateUrl: 'my-store.component.html', 
 directives: [ROUTER_DIRECTIVES],
 providers: [ROUTER_PROVIDERS]
 }) @Routes([
 {path: '/products', component: ProductListComponent},
 {path: '/product/:id', component: ProductComponent}
 ])
 export class MyStoreComponent { constructor(private router: Router) {} 
 }
  55. Router Outlet <router-outlet></router-outlet> @Routes([
 {path: '/products', component: ProductListComponent},
 {path: '/product/:id',

    component: ProductComponent}
 ])
 export class MyStoreComponent { constructor(private router: Router) {} } my-store
  56. Router Links <a [routerLink]="['/products']">All Products</a> <router-outlet></router-outlet> @Routes([
 {path: '/products', component:

    ProductListComponent},
 {path: '/product/:id', component: ProductComponent}
 ])
 export class MyStoreComponent { constructor(private router: Router) {} } my-store
  57. Router Links <a [routerLink]="['/products']">All Products</a> <a [routerLink]="['/product', productId]"> Product {{

    productId }} - {{ productName }}</a> <router-outlet></router-outlet> @Routes([
 {path: '/products', component: ProductListComponent},
 {path: '/product/:id', component: ProductComponent}
 ])
 export class MyStoreComponent { constructor(private router: Router) {} } my-store
  58. Router Links <a [routerLink]="['/products']">All Products</a> <a [routerLink]="['/product', productId]"> Product {{

    productId }} - {{ productName }}</a> <button (click)="goToProduct(productId)"> {{ productName }}</button> <router-outlet></router-outlet> @Routes([
 {path: '/products', component: ProductListComponent},
 {path: '/product/:id', component: ProductComponent}
 ])
 export class MyStoreComponent { constructor(private router: Router) {} goToProduct(id) {
 this.router.navigate(['/product', id]);
 } } my-store
  59. Fetching route params import { Component } from '@angular/core'; import

    { RouteSegment } from '@angular/router';
 @Component({
 moduleId: module.id,
 selector: 'product',
 templateUrl: 'product.component.html', 
 }) 
 export class ProductComponent { selectedId: number; routerOnActivate(currentRoute: RouteSegment) {
 this.selectedId = +currentRoute.getParam('id');
 } 
 } product
  60. styleUrls import { Component } from '@angular/core'; 
 @Component({
 moduleId:

    module.id,
 selector: 'product',
 template: `<h1>{{ product.title }}</h1>`, styleUrls: ['product.component.css'], 
 })
 
 export class ProductComponent {}
  61. styles (inline) import { Component } from '@angular/core'; 
 @Component({


    moduleId: module.id,
 selector: 'product',
 template: `<h1>{{ product.title }}</h1>`, styleUrls: ['product.component.css'], styles: [ `h1 { background-color: yellow; } button { height: 30px; background-color: aqua; border-radius: 5px; }`, 'button {font-size: 16px;}' ] 
 })
 
 export class ProductComponent {}
  62. CSS special selector :host import { Component } from '@angular/core';

    
 @Component({
 moduleId: module.id,
 selector: 'product',
 template: `<h1>{{ product.title }}</h1>`, styleUrls: ['product.component.css'], styles: [ ` :host { display: block; padding: 10px; border: 1px solid purple; background-color: yellow; }` ] })
 export class ProductComponent {} // parent component template <product></product> product
  63. CSS special selector :host-context() import { Component } from '@angular/core';

    
 @Component({
 moduleId: module.id,
 selector: 'product',
 template: `<h1>{{ product.title }}</h1>`, styleUrls: ['product.component.css'], styles: [ ` :host-context(.best-seller) h1 { border: 2px yellow solid; }` ] 
 }) 
 export class ProductComponent {} // parent component template <product></product> product .best-seller h1
  64. CSS special selector /deep/ import { Component } from '@angular/core';

    
 @Component({
 moduleId: module.id,
 selector: 'product',
 template: `<h1>{{ product.title }}</h1>`, styleUrls: ['product.component.css'], styles: [ ` :host /deep/ h1 { font-style: italic; }` ] }) 
 export class ProductComponent {} // parent component template <product></product> product prod-title h1
  65. import { Component, ViewEncapsulation } from '@angular/core'; 
 @Component({
 moduleId:

    module.id,
 selector: 'product',
 template: `<h1>{{ product.title }}</h1>`, styleUrls: ['product.component.css'], styles: [ `:host /deep/ h1 { font-style: italic; } h1 { border: 1px solid red; }` ], encapsulation: ViewEncapsulation.Emulated }) 
 export class ProductComponent {} // parent component template <product></product> View encapsulation: emulated app style product
  66. View encapsulation: native import { Component, ViewEncapsulation } from '@angular/core';

    
 @Component({
 moduleId: module.id,
 selector: 'product',
 template: `<h1>{{ product.title }}</h1>`, styleUrls: ['product.component.css'], styles: [ `:host /deep/ h1 { font-style: italic; } h1 { border: 1px solid red; }` ], encapsulation: ViewEncapsulation.Native }) 
 export class ProductComponent {} // parent component template <product></product> app style product
  67. import { Component, ViewEncapsulation } from '@angular/core'; 
 @Component({
 moduleId:

    module.id,
 selector: 'product',
 template: `<h1>{{ product.title }}</h1>`, styleUrls: ['product.component.css'], styles: [ `:host /deep/ h1 { font-style: italic; } h1 { border: 1px solid red; }` ], encapsulation: ViewEncapsulation.None }) 
 export class ProductComponent {} // parent component template <product></product> View encapsulation: none app style product