Arquivo da tag: AngularJS2

Understanding Angular 2 Components for AngularJS Devs

What is it like to build an Angular 2 app, and how is the experience different from AngularJS?

Angular 2 is component based. Components combine concepts that we are already familiar with from AngularJS. The Angular 2 Component combines the AngularJS Directive, Controller, and Scope. My article will attempt to make you more comfortable with components by comparing them to what you already know from AngularJS.

Here are some tutorials that I worked through to prepare this. I will periodically link to code examples from them: Quickstart & Tour of Heroes

TypeScript is recommended for Angular 2. You will see the .ts file extension. I will point out TypeScript syntax where needed.

Bootstrapping the Top Level Component

Here is an example of an Angular 2 component, app.component.ts, that I’ve copied below from the Angular 2 Tutorial.
[code type=typescript]
import { Component, OnInit } from ‘@angular/core’;

import { Hero } from ‘./hero’;
import { HeroDetailComponent } from ‘./hero-detail.component’;
import { HeroService } from ‘./hero.service’;

@Component({
selector: ‘my-app’,
template: ‘

{{title}}

My Heroes


  • {{hero.id}} {{hero.name}}


‘,
styles: [‘
.heroes {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 15em;
}
‘],
directives: [HeroDetailComponent],
providers: [HeroService]
})

export class AppComponent implements OnInit {
title = ‘Tour of Heroes’;
heroes: Hero[];
selectedHero: Hero;

constructor(private heroService: HeroService) { }

getHeroes() {
this.heroService.getHeroes().then(heroes => this.heroes = heroes);
}

ngOnInit() {
this.getHeroes();
}

onSelect(hero: Hero) { this.selectedHero = hero; }
}

Before we delve into the details, let me describe what is happening here at a high level. First we import any referenced classes using TypeScript modules at the top. Next we configure the component using the @Component decorator. The decorator is a feature of TypeScript. Finally, we define the component’s properties and behavior then export it.

Angular 2 apps will have one main, top-level Component. Using the ES6 module system (supported by TypeScript), we can kick-off the application by importing the AppComponent and bootstrapping it as the main component like this:
[code type=typescript]
// main.ts
import {bootstrap} from ‘angular2/platform/browser’;
import {AppComponent} from ‘./app.component’;

bootstrap(AppComponent);

Loading main.js in a <script> tag will start the app on the page through it’s top-level component.

The @Component Decorator

TypeScript decorators, like @Component, are functions that modify the class defined below. The Angular 2 @Component decorator is a configuration much like the AngularJS Directive. Compare the following AngularJS Directive to the Angular 2 @Componentdecorator above.
[code type=typescript]
directive(‘myHero’, function() {
return {
restrict: ‘E’,
scope: {
customerInfo: ‘=info’
},
templateUrl: ‘my-hero.html’,
controller: ‘HeroController’,
controllerAs: ‘heroCtrl’
};
});

Components and directives define the HTML markup to use. Components also define the styles attribute where directives do not. In components, styles are encapsulated. They do not “leak” to elements in the outer HTML or to other Components. This is enabled by some improvements in HTML itself.

Styles and HTML markup need not be defined inline. @Component provides the templateUrl and styleUrl properties all alternative to template and style.
[code type=typescript]
@Component({
selector: ‘my-dashboard’,
templateUrl: ‘app/dashboard.component.html’,
styleUrls: [‘app/dashboard.component.css’]
})

Components Continued

Angular 2 components make some decisions for you that directives didn’t. For example, Angular 2 components:

  • Always isolate scope (instead of sharing a parent scope)
  • Always restrict ‘E’ (load into custom elements in the DOM)
  • Always bind to a controller (as opposed to $scope)

AngularJS applications that adhere to the John Papa Style Guide already use these conventions. I would strongly recommend referencing the guide while developing your AngularJS apps.

Component Class Definition

Angular 2 component class definitions do the same job as our AngularJS controllers. At the bottom of app.component.ts we export the AppComponent component class definition. It’s where we define and initialize the state of our component and define the component’s behaviour as functions that events on the page bind to.
[code type=typescript]
import {Component, OnInit} from ‘angular2/core’;
import {Hero} from ‘./hero’;
import {HeroDetailComponent} from ‘./hero-detail.component’;
import {HeroService} from ‘./hero.service’;

@Component({
selector: ‘my-app’,
template:’

{{title}}

My Heroes


  • {{hero.id}} {{hero.name}}


‘,
directives: [HeroDetailComponent],
providers: [HeroService]
})

export class AppComponent implements OnInit {
title = ‘Tour of Heroes’;
heroes: Hero[];
selectedHero: Hero;

constructor(private _heroService: HeroService) { }

getHeroes() {
this._heroService.getHeroes().then(heroes => this.heroes = heroes);
}

ngOnInit() {
this.getHeroes();
}

onSelect(hero: Hero) { this.selectedHero = hero; }
}

Angular 2 provides the ngOnInit lifecycle hook for you to step in and initialize the component. We initialize data through the ngOnInit hook instead of through the constructor to limit side effects in our tests. Notice we only use the constructor function to wire things up.

Component Interactions

AppComponent will render itself into <my-app>, by setting its own element selector to my-app in the @Component decorator. It will also render a HeroDetailComponent into <my-hero-detail>. It does a few things to make this happen:

  • Imports the HeroDetailComponent class
  • Registers the HeroDetailComponent in its directives metadata array
  • Provides the <my-hero-detail> element in its template markup
  • Sets the values of HeroDetailComponent’s input properties through <my-hero-detail>’s element attributes

Here is the implementation of the HeroDetailComponent:
[code type=typescript]
import { Component, Input } from ‘@angular/core’;
import { Hero } from ‘./hero’;

@Component({
selector: ‘my-hero-detail’,
template: ‘

{{hero.name}} details!

{{hero.id}}


})
export class HeroDetailComponent {
@Input() hero: Hero;
}

When the app is bootstrapped, AppComponent is directed through its selector property to seek out a <my-app> element on the page to render itself into. Its sub-component, HeroDetailComponent, will similarly seek out a <my-hero-detail> element through its selector property.

The <my-hero-detail> element is provided in the markup of the HeroDetail’s parent component, AppComponent, and the <my-app> element is provided in index.html. Users of angular ui-router will recognize this pattern of rendering nested views into <ui-view>elements.

When the user selects a hero, AppComponent is responsible for passing that information along to the HeroDetailComponent.

<my-hero-detail [hero]="selectedHero"></my-hero-detail>

In the <my-hero-detail> element, the AppComponent binds the hero property of the HeroDetailComponent to the current value of its selectedHero property. We also declare hero as an @Input property HeroDetailComponent’s class definition (see HeroDetailComponent code above). The interesting side-effect of this is that data-binding on selectedHero, and the <div *ngIf="hero"> in HeroDetailComponent’s template is the trigger that renders the my-hero-detail component on the page.

A property that is bound in this way, through a sub-component’s element, must be declared as an @Input() in the sub-component. Failing to do so will force Angular 2 to reject the binding and throw an error. In Angular 2, we explicitly declare bindable properties as @Input(), so that we can protect internal properties from being munged from the outside.

The bracket syntax on [hero] represents a property data binding. This is a one-way binding of currentHero from the component to an element. Angular 2 adds new template syntax to represent different bindings in the markup.

One-way binding means the value of currentHero cannot be updated by hero-detail. A two-way binding to currentHero would be represented like [(hero)] = "currentHero". This example doesn’t touch all the types of data-binding in Angular 2. You can read more about event bindings, etc, here.

Dependency Injection

AppComponent depends on the HeroService in order to access the application’s hero data. We register the HeroService as a dependency in the @Component decorator’s providers property. In our providers array we define the services we are interested in, and they are made available in our component’s constructor.

Notice that we do not re-declare the HeroService as a dependency of the HeroDetailcomponent. Dependencies need not be re-declared in sub-components, and doing so could be detrimental. Redeclaring HeroService in this way would give HeroDetail a new instance of the HeroService. This defeats the purpose of the service, which is to share the same data amongst different components.

https://teamgaslight.com/blog/understanding-angular-2-components-for-angularjs-devs

Criando um CRUD com Angular 2 + Rails 5

Introdução ?

Os Apps profissionais seguem há algum tempo na direção de ter uma divisão entre o backend (API) e o front end (Cliente Web), recentemente foi lançado a versão 2 do Angular (que tem pouco a ver com a versão 1) e também a versão 5 do Rails (que tem muito a ver com a versão 4 ? ), nesse tutorial eu vou demonstrar como conectar essas duas tecnologias para criar um App incrível \o/.

Nós vamos criar um CRUD de uma pequena aplicação de FAQ, e para fazer isso mais rapidamente nós vamos usar uma ferramenta bem legal que chama Angular-CLI (command line interface), que vai nos permitir gerar o projeto Angular 2, os components e os services facilmente (similar aos generates do Rails).

O que vamos aprender?
  1. Como criar um CRUD em uma aplicação Rails 5
  2. Como criar um CRUD em uma aplicação Angular 2
  3. Como conectar o Rails 5 com o Angular 2
INGREDIENTES
Objetivos

Criar um Pequeno App que nos permita criar questões para um FAQ, com o front end em Angular 2 e o Backend no Rails 5.

Passo a Passo
  • Rails 5
    1. Criar o Projeto Rails Api
    2. Gerar o CRUD
    3. Incluir o CORS
  • Angular 2
    1. Criar o Projeto Angular usando o Angular-CLI
    2. Configurar nosso projeto
    3. Criar nossos components
    4. Criar nosso service
    5. Editar nossas views
    6. Conectar tudo isso ?
Mãos à Obra \o/
Parte 1 – Criando o projeto Rails 5

Primeiro vamos gerar o nosso projeto Rails 5 API que vai ser consumido via JSON pelo projeto Angular 2.

  1. Para começar, rode no seu console o comando para gerar o projeto:

    *a flag –api significa que o rails vai configurar o projeto como uma API pra gente

  2. Agora vamos gerar nosso scaffold, rode:
  3. Rode as migrations:
  4. Agora vamos configurar o CORS para que nosso APP possa receber chamada de outros domínios, primeiro no seu Gemfile adicione:

    *O que é CORS

  5. Rode o bundle, para instalar a Gem:
  6. Agora no arquivo config/application.rb, substitua o conteúdo por:
  7. Para testar, rode o servidor e visite http://localhost:3000/questions
  8. Pronto \o/, nossa aplicação Rails já está pronta. Agora vamos para o Angular 2 ?

 

Pausa para o Merchan do BEM! ?
BOOTCAMP ONE BIT CODE – SUBA DE LEVEL NO MUNDO DO RUBY ON RAILS

Este é o último final de semana para se inscrever no primeiro Bootcamp online do OneBitCode!
Neste curso, nós vamos criar do zero um site similar ao Airbnb usando Rails 5 como Api e Angular 2 como cliente Web.
O curso vai ter vídeo aulas semanais, live de 2 horas por semana, suporte total às dúvidas e um Slack exclusivo para os alunos desenvolverem network.
O curso vai ser ÉPICO, então confere a Landing Page dele e faça parte do grupo de alunos One Bit Code! \o/
Conheça o Bootcamp!

Parte 2 – Criando o App Angular 2

Agora sim começa a parte mais emocionante complicada, vamos criar nosso APP Angular 2 e para fazer isso vamos usar o Angular-CLI.

Dependências

Primeiro, vamos começar com as dependências.

  1. Você vai precisar ter o NPM instalado na sua máquina. Para instalar no Ubuntu:

    Para instalar no Mac:

  2. Agora você precisa instalar o Angular-CLI:
Criação do App

Finalmente, vamos a criação do App.

  1. Para gerar o projeto, rode na pasta desejada (fora do projeto Rails) no console:
  2. Agora vamos ver se tudo funcionou corretamente, dentro do projeto, rode no console:
  3. Acesse no seu browser, http://localhost:9000, deve aparecer uma mensagem dizendo que funcionou ?
  4. Agora vamos gerar nossos components, rode:

    *Os components são o coração do Angular 2, eles são a principal maneira que nós criamos elementos, definimos as views e a lógica

  5. Depois rode:
  6. Agora vamos gerar nosso Modelo de dados, crie uma pasta no caminho “/src/app/questions/” com o nome shared (“/src/app/questions/shared”).
  7. Depois crie um arquivo dentro dessa pasta chamado “question.ts” e coloque o seguinte conteúdo:
  8. Vamos criar nosso Service (ele serve para o Angular 2 conversar com a API), no console rode o comando:
  9. Agora vamos adicionar o router outlet para fazer nossas rotas funcionarem, no nosso arquivo ‘src/app/app.componet.html’ substitua o conteúdo por:
  10. Agora nós vamos criar o nosso arquivo de rotas (que vai gerenciar nossas URLs), no caminho “src/app/” crie o arquivo “app.routing.ts” e preencha ele com o seguinte conteúdo:
    *Note os comentários no código

  11. Agora nós precisamos alterar nosso arquivo ‘src/app/app.module.ts’ para incluir nosso arquivo de rotas e algumas dependências do projeto, seu arquivo deve ficar assim:
    *Note os comentários no código

  12. Agora nós vamos editar nossos components, para começar vamos editar nosso componente de listagem, no arquivo ‘/src/app/questions/questions.component.ts’ substitua o conteúdo por:
    *Note os comentários no código

  13. Pronto, a parte lógica da listagem está ok (exceto pelo service ainda), agora vamos editar a aparência da aplicação, no arquivo ‘/src/app/questions/questions.component.html’ adicione o seguinte html:
  14. Agora vamos para o próximo component, no arquivo /src/app/questions/question-form/question-form.component.ts’ cole o seguinte código para podermos editar e criar questions:
    *Note os comentários no código

  15. Pronto, a parte lógica da edição/criação está ok (exceto pelo service ainda), agora vamos editar a aparência da aplicação, no arquivo ‘/src/app/questions/question-form/question-form.component.html’ adicione o seguinte html:
  16. Excelente, nossos components estão ok, agora vamos configurar nosso service. No arquvio ‘src/app/questions/shared/questions.service.ts’ susbstitua o conteúdo pelo seguinte código:
    *Note os comentários no código

  17. Pronto \o/, agora vamos testar.
  18. Rode no seu console:
  19. Acessando no browser, seu resultado deve ser similar a este:
    captura-de-tela-de-2016-12-10-02-49-37* É claro que não é um Faq muito bonito, mas ele funciona e é suficiente para demonstrar a integração ?
  20. Agora você pode criar novas questões, editá-las e deletá-las \o/, parabéns nós conseguimos!

 

CONCLUSÃO

Pronto, conseguimos fazer o nosso não tão simples CRUD, mas valeu a pena :). É claro que esse é um tutorial introdutório apenas para te dar uma visão geral de como o Angular 2 e o Rails 5 podem se comunicar e também para abrir um pouco a sua mente para a estrutura do Angular 2. Mas tenho certeza que você notou a riqueza dos dois frameworks e as possibilidades ilimitadas que eles trazem se usados juntos ?

Como de costume o Código completo da aplicação está no Github, caso você queria clonar o código, clique aqui para ver a parte do Angular 2 e clique aqui para acessar a parte do Rails 5. Aproveita e me segue lá \o/

Apenas informando novamente que o Bootcamp do OneBitCode está com as inscrições abertas (quase fechando já) e nesse bootcamp nós vamos nos aprofundar muito no Rails 5 e também no Angular 2 (fullstack) através da criação de um clone do Airbnb, então se você ainda não viu a landing page, VEJA CLICANDO AQUI. Vai ser épico, não deixe essa chance passar! \o/

Se você ficou com dúvidas ou tem sugestões de posts para o Blog comenta aí em baixo ou me adiciona no Facebook clicando aqui.

 

Angular 2 – Hello World (es5)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script src="https://code.angularjs.org/2.0.0-alpha.23/angular2.sfx.dev.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<body>
 
  <egghead></egghead>
 
</body>
</html>

Javascript

function Note(){}
Note.annotations = [
    new angular.ComponentAnnotation({
        selector: "note"
    }),
    new angular.ViewAnnotation({
        template: "<div>Simple message</div>"
    })
];
 
function Egghead(){}
Egghead.annotations = [
    new angular.ComponentAnnotation({
        selector: "egghead"
    }),
    new angular.ViewAnnotation({
        directives: [Note],
        template: "<div><h1>Hello everyone</h1><note></note></div>"
    })
];
 
document.addEventListener("DOMContentLoaded", function(){
    angular.bootstrap(Egghead);
});

Angular 2 – Binding (es5)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script src="https://code.angularjs.org/2.0.0-alpha.22/angular2.sfx.dev.js"></script>
</head>
<body>
 
  <clock></clock>
 
</body>
</html>

Javascript

 
function Clock(){
    var clock = this;
    clock.time = 0;
    clock.message = "I'm a clock!";
 
    setInterval(function(){
        clock.time++;
    }, 1000);
}
Clock.annotations = [
    new angular.ComponentAnnotation({
        selector: "clock"
    }),
    new angular.ViewAnnotation({
        template: '{{message}} {{time}}'
    })
];
 
document.addEventListener("DOMContentLoaded", function(){
    angular.bootstrap(Clock);
})

Angular 2 – Events (es5)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script src="https://code.angularjs.org/2.0.0-alpha.23/angular2.sfx.dev.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<body>
 
  <app></app>
 
</body>
</html>

Javascript

//Sublime snippets used in the video: https://gist.github.com/johnlindquist/252f29e087219be7e11a
function Clicker(){
    this.clickCounter = 0;
    this.x = 0;
    this.y = 0;
 
    this.onClick = function onClick(){
        this.clickCounter++;
    };
 
    this.onMouseMove = function onMouseMove(event){
        this.x = event.x;
        this.y = event.y;
    };
}
Clicker.annotations = [
    new angular.ComponentAnnotation({
        selector: "clicker"
    }),
    new angular.ViewAnnotation({
        template: '<div>\
          <button (mousemove)="onMouseMove($event)" (click)="onClick()">{{clickCounter}}</button>\
          {{x}}, {{y}}\
        </div>'
    })
];
 
 
function App(){}
App.annotations = [
    new angular.ComponentAnnotation({
        selector: "app"
    }),
    new angular.ViewAnnotation({
        directives: [Clicker],
        template: '<div>\
          <h1>App</h1>\
          <clicker></clicker>\
        </div>'
    })
];
 
document.addEventListener("DOMContentLoaded", function(){
    angular.bootstrap(App);
});

Angular 2 – Custom Events (es5)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script src="https://code.angularjs.org/2.0.0-alpha.23/angular2.sfx.dev.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<body>
 
  <app></app>
 
</body>
</html>

Javascript

function Clicker(){
    this.value = 0;
    this.update = new angular.EventEmitter();
 
    this.onClick = function onClick(event){
        this.value++;
        this.update.next({value:this.value});
    };
 
    this.onMouseout = function onMouseout(event){
        this.value = 0;
        this.update.next({value:this.value});
    };
}
Clicker.annotations = [
    new angular.ComponentAnnotation({
        events: ["update"],
        selector: "clicker"
    }),
    new angular.ViewAnnotation({
        template: '<div>\
            <button \
                (mouseout)="onMouseout($event)" \
                (click)="onClick($event)">\
                Click me!\
            </button>\
        </div>'
    })
];
 
 
function App(){
    this.clickerValue = 0;
    this.onUpdate = function onUpdate(event){
        this.clickerValue = event.value;
    };
}
App.annotations = [
    new angular.ComponentAnnotation({
        selector: "app"
    }),
    new angular.ViewAnnotation({
        directives: [Clicker],
        template: '<div>\
          <h1>App</h1>\
          <clicker (update)="onUpdate($event)"></clicker>\
          {{clickerValue}}\
        </div>'
    })
];
 
document.addEventListener("DOMContentLoaded", function(){
    angular.bootstrap(App);
});

Angular 2 – First Directive (es5)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script src="https://code.angularjs.org/2.0.0-alpha.23/angular2.sfx.dev.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<body>
 
  <app></app>
 
</body>
</html>

Javascript

function Clicky(){
    this.textContent = "is this thing on?";
 
    this.onClick = function onClick(event){
        this.textContent = "you clicked my host";
    }
}
Clicky.annotations = [
    new angular.DirectiveAnnotation({
        selector: "[clicky]",
 
        hostListeners: {
            "click": "onClick()"
        },
        hostProperties: {
            "textContent": "textContent"
        }
    })
];
 
 
 
function App(){}
App.annotations = [
    new angular.ComponentAnnotation({
        selector: "app"
    }),
    new angular.ViewAnnotation({
        directives:  [Clicky],
        template: "<div>\
          <h1 clicky>Egghead App</h1>\
        </div>"
    })
];
 
 
document.addEventListener("DOMContentLoaded", function(){
    angular.bootstrap(App);
});