Angular 2 – Создаём CRUD приложение с помощью Angular CLI
Тип Поста

Angular 2 – Создаём CRUD приложение с помощью Angular CLI

Angular 2 – Создаём CRUD приложение с помощью Angular CLI

Angular 2 – это open source фреймворк для создания мобильных, десктопных и веб-приложений.

Angular 2 хоть и является приемником AngularJS 1.x, но может быть рассмотрен как совершенно новый фреймворк, созданный на основе лучших наработок из AngularJS 1.x. Отсюда пошло изменение в его именовании – теперь используется просто имя Angular, что указывает именно на Angular 2. В свою очередь, имя AngularJS ссылается на прошлую версию AngularJS 1.x. В этой статье мы будем использовать имена Angular и Angular 2 попеременно, но они оба ссылаются на Angular 2.

В данной статье мы создадим небольшое Angular 2 веб-приложение, которое позволит делать следующие вещи:

  • Быстро создавать новые записи, используя поле ввода, простым нажатием клавиши Enter
  • Выбирать статус записи
  • Удалять ненужные записи
angular2-crud-cli-01

По этой ссылке доступно демо приложения. Все исходные коды приложения можно найти в GitHub репозитории.

Итак, давайте начнём!

Angular CLI

Одним из самых простых способов создать новое Angular 2 приложение – использовать интерфейс командной строки (CLI) для Angular от разработчиков этого фреймворка, который позволит:

  • Создать стартовый шаблон со всем необходимым кодом для нового Angular 2 приложения
  • Добавить необходимые компоненты, директивы, сервисы, pipes и т.д. к существующему приложению

Для установки Angular CLI необходимо запустить в командной строке:

npm install -g angular-cli

В данном случае, параметр -g указывает на то, что этот пакет установится глобально и после этого нам будет доступна команда ng.

Чтобы проверить правильность установки, можно выполнить такую команду:

ng version

Если всё установлено верно, то будет выведена версия пакета.

angular2-crud-cli-09
При необходимости, вы можете посетить официальную документацию для более детального ознакомления c Angular CLI.

Генерируем наше приложение

Теперь, когда у нас есть установленный Angular CLI, мы можем использовать его для создания стартового шаблона для нашего приложения:

ng new angular2-todo-app

Этой командой мы создадим новую директорию для нашего проекта со всем необходимым для начала работы.

angular2-crud-cli-02

После генерации шаблона, выполним следующие команды:

# Перейти в новую директорию, созданную для нас CLI
cd angular2-todo-app

# Запустить локальный сервер разработки
ng serve

Тем самым, у нас будет запущенный локальный сервер, который обслуживает наше приложение и доступен по адресу http://localhost:4200/. Также при изменении кода, наше приложение будет автоматически перезагружаться, что добавит немного комфорта в процесс разработки.

angular2-crud-cli-03

Составные части Angular

При выполнении команды ng new, Angular CLI создал для нас стартовый Angular 2 шаблон, но это только лишь одна из полезных возможностей, предоставляемых этим инструментом. Этот инструмент также поможет нам добавить дополнительные составные части в существующее Angular приложение, при помощи команды ng generate:

# Создать новый компонент
ng generate component my-new-component

# Создать новую директиву
ng generate directive my-new-directive

# Создать новый pipe
ng generate pipe my-new-pipe

# Создать новый сервис
ng generate service my-new-service

# Создать новый класс
ng generate class my-new-class

# Создать новый интерфейс
ng generate interface my-new-interface

# Создать новый enum
ng generate enum my-new-enum
Если вы не знакомы с основными строительными блоками Angular 2 приложения, то крайне рекомендую ознакомиться с быстрым стартом Angular 2 сначала.

Для нашего приложения нам понадобятся:

  • Todo класс для представления каждой отдельной записи
  • TodoService для создания, обновления и удаления записи
  • TodoApp компонент для отображения пользовательского интерфейса

Итак, давайте добавим последовательно все эти компоненты в наше приложение.

Создание класса Todo

По той причине, что мы используем TypeScript, у нас есть возможность создать класс для представления Todo записей. Поэтому, воспользуемся возможностями Angular CLI для генерации Todo класса:

ng generate class Todo

Что создаст следующие файлы:

src/app/todo.spec.ts
src/app/todo.ts

Давайте откроем файл src/app/todo.ts и заменим его содержимое на:

export class Todo {
  id: number;
  title: string = '';
  complete: boolean = false;

  constructor( values: Object = {} )
  {
    Object.assign( this, values );
  }
}

В нашем случае, каждая Todo запись имеет три свойства:

  • id: числовой тип, уникальный ID каждой записи
  • title: строковый тип, название записи
  • complete: булевый тип, статус для записи – завершена задача или нет

Использование конструктора позволит нам при создании экземпляра класса определить нужные значения, например:

let todo = new Todo({
  title: 'Прочитать статью до конца',
  complete: false
});

Angular CLI также создал для нас src/app/todo.spec.ts файл, поэтому давайте добавим в него юнит-тест, чтобы убедиться в работоспособности логики конструктора:

import {
  beforeEach, beforeEachProviders,
  describe, xdescribe,
  expect, it, xit,
  async, inject
} from '@angular/core/testing';

import { Todo } from './todo';

describe( 'Todo', () =>
{
  it( 'должно создать экзепляр класса', () =>
  {
    expect( new Todo() ).toBeTruthy();
  });

  it( 'должно принять значения в конструктор', () =>
  {
    let todo = new Todo( {
      title: 'привет',
      complete: true
    } );

    expect( todo.title ).toEqual( 'привет' );
    expect( todo.complete ).toEqual( true );
  });
});

Для проверки того, что наш код работает так, как мы ожидали, запустим юнит-тесты командой:

ng test

Которая запустит окружение для тестирования Karma и выполнит все наши тесты.

Если тесты не были пройдены успешно, то, возможно, вы допустили какую-то ошибку в коде приложения. Просто сравните ваш код с кодом, находящимся в репозитории приложения: https://github.com/sbogdanov108/angular2_crud
angular2-crud-cli-04

Теперь, когда у нас есть Todo класс, давайте создадим Todo сервис, который будет управлять всеми записями нашего приложения.

Создание Todo сервиса

TodoService, который будет нами создан, должен отвечать за управление Todo записями. В будущей статье, мы разберём, как взаимодействовать с REST API сервисом, но в рамках данной статьи, мы используем простое хранение всех данных приложения в оперативной памяти.

Приступим к генерации нового сервиса с помощью Angular CLI:

ng generate service Todo

Этой командой мы создадим файлы:

src/app/todo.service.spec.ts
src/app/todo.service.ts

Сейчас нам нужно добавить логику работу сервиса TodoService в файл src/app/todo.service.ts:

import { Injectable } from '@angular/core';
import { Todo } from './todo';

@Injectable()
export class TodoService
{
  /*
  * Значение для последнего ИД,
  * с помощью которого, мы будем имитировать автоматическое увеличение ИД
  * */
  lastId: number = 0;

  /*
  * Массив, в котором будут храниться записи
  * */
  todos: Todo[] = [];

  constructor() {}

  /*
  * Имитируем метод POST при обращении к /todos
  * */
  addTodo( todo: Todo ): TodoService
  {
    if( !todo.title )
    {
      return;
    }

    if ( !todo.id )
    {
      todo.id = ++this.lastId;
    }

    this.todos.push( todo );

    return this;
  }

  /*
   * Имитируем метод DELETE при обращении к /todos/:id
   * */
  deleteTodoById( id: number ): TodoService
  {
    this.todos = this.todos
      .filter( todo => todo.id !== id );

    return this;
  }

  /*
   * Имитируем метод PUT при обращении к /todos/:id
   * */
  updateTodoById( id: number, values: Object = {} ): Todo
  {
    let todo = this.getTodoById( id );

    if ( !todo )
    {
      return null;
    }

    Object.assign( todo, values );

    return todo;
  }

  /*
   * Имитируем метод GET при обращении к /todos
   * */
  getAllTodos(): Todo[]
  {
    return this.todos;
  }

  /*
   * Имитируем метод GET при обращении к /todos/:id
   * */
  getTodoById( id: number ): Todo
  {
    return this.todos
      .filter( todo => todo.id === id )
      .pop();
  }

  /*
   * Изменить статус записи
   * */
  toggleTodoComplete( todo: Todo )
  {
    let updatedTodo = this.updateTodoById( todo.id, {
      complete: !todo.complete
    } );

    return updatedTodo;
  }
}

Детали реализации описанных выше методов не являются темой данной статьи и могут иметь любую логику работы, удовлетворяющей вашим потребностям. Основной смысл данных действий в том, что мы вынесли бизнес-логику нашего приложения в отдельный сервис.

И чтобы убедиться, что написанная нами логика работает, давайте добавим несколько юнит-тестов в файл src/app/todo.service.spec.ts, который был сгенерирован Angular CLI.

Так как Angular CLI уже создал для нас заготовку кода, всё, что остаётся сделать – реализовать нужные тесты:

import {
  beforeEach, beforeEachProviders,
  describe, xdescribe,
  expect, it, xit,
  async, inject
} from '@angular/core/testing';

import { Todo } from './todo';
import { TodoService } from './todo.service';

describe( 'Todo Service', () =>
{
  beforeEachProviders( () => [ TodoService ] );

  describe('#getAllTodos()', () =>
  {
    it( 'должно возвращать пустой массив по молчанию', inject( [ TodoService ], ( service: TodoService ) =>
    {
      expect( service.getAllTodos() ).toEqual( [] );
    }) );

    it( 'должно возвращать все todos', inject( [ TodoService ], ( service: TodoService ) =>
    {
      let todo1 = new Todo({ title: 'Привет 1', complete: false });
      let todo2 = new Todo({ title: 'Привет 2', complete: true });

      service.addTodo( todo1 );
      service.addTodo( todo2 );

      expect( service.getAllTodos() ).toEqual( [ todo1, todo2 ] );
    }) );
  });

  describe( '#save(todo)', () =>
  {
    it( 'должно автоматически назначать увеличенный ид', inject( [ TodoService ], ( service: TodoService ) =>
    {
      let todo1 = new Todo({ title: 'Hello 1', complete: false });
      let todo2 = new Todo({ title: 'Hello 2', complete: true });

      service.addTodo( todo1 );
      service.addTodo( todo2 );

      expect( service.getTodoById( 1 ) ).toEqual( todo1 );
      expect( service.getTodoById( 2 ) ).toEqual( todo2 );
    }) );
  });

  describe( '#deleteTodoById(id)', () =>
  {
    it( 'должно удалять todo по соответствующему ид', inject( [ TodoService ], ( service: TodoService ) =>
    {
      let todo1 = new Todo({ title: 'Hello 1', complete: false });
      let todo2 = new Todo({ title: 'Hello 2', complete: true });

      service.addTodo( todo1 );
      service.addTodo( todo2 );

      expect( service.getAllTodos() ).toEqual([ todo1, todo2 ]);
      service.deleteTodoById( 1 );

      expect( service.getAllTodos() ).toEqual([ todo2 ]);
      service.deleteTodoById( 2 );

      expect( service.getAllTodos() ).toEqual([]);
    }) );

    it( 'не должно ничего удалять, если todo с соответствующим ид не найдено', inject( [ TodoService ], ( service: TodoService ) =>
    {
      let todo1 = new Todo({ title: 'Hello 1', complete: false });
      let todo2 = new Todo({ title: 'Hello 2', complete: true });

      service.addTodo(todo1 );
      service.addTodo(todo2 );

      expect( service.getAllTodos() ).toEqual([ todo1, todo2 ]);
      service.deleteTodoById( 3 );
      expect( service.getAllTodos() ).toEqual([ todo1, todo2 ]);
    }) );
  });

  describe( '#updateTodoById(id, values)', () =>
  {
    it( 'должно возвращать todo с соответствующим ид и обновленными данными', inject( [ TodoService ], ( service: TodoService ) =>
    {
      let todo = new Todo({ title: 'Hello 1', complete: false });

      service.addTodo( todo );
      let updatedTodo = service.updateTodoById( 1, {
        title: 'новое название'
      } );

      expect( updatedTodo.title ).toEqual( 'новое название');
    }) );

    it( 'должно вернуть null, если todo не найден', inject( [ TodoService ], ( service: TodoService ) =>
    {
      let todo = new Todo({ title: 'Hello 1', complete: false });

      service.addTodo(todo);
      let updatedTodo = service.updateTodoById( 2, {
        title: 'новое название'
      });

      expect( updatedTodo ).toEqual( null );
    }) );
  });

  describe( '#toggleTodoComplete(todo)', () =>
  {
    it( 'должно вернуть обновленный todo с противоположным статусом', inject( [ TodoService ], ( service: TodoService ) =>
    {
      let todo = new Todo({ title: 'Hello 1', complete: false });

      service.addTodo( todo );
      let updatedTodo = service.toggleTodoComplete( todo );

      expect( updatedTodo.complete ).toEqual( true );
      service.toggleTodoComplete( todo );
      expect( updatedTodo.complete ).toEqual( false );
    }) );
  });
});
Karma поставляется с встроенным и предварительно сконфигурированным фреймворком для тестирования Jasmine. Вы можете ознакомиться с документацией Jasmin для лучшего понимания синтаксиса этого фреймворка.

Чтобы проверить правильность работы нашей бизнес-логики, заново запустим наши юнит-тесты:

ng test
angular2-crud-cli-05

Отлично, всё работает! Теперь самое время создать интерфейс нашего приложения.

В Angular 2 интерфейс приложения реализуется с помощью компонентов.

Создание TodoApp компонента

И снова давайте используем Angular CLI для генерации компонента:

ng generate component TodoApp

Эта команда создаст следующие файлы:

create src\app\todo-app\todo-app.component.css
create src\app\todo-app\todo-app.component.html
create src\app\todo-app\todo-app.component.spec.ts
create src\app\todo-app\todo-app.component.ts
create src\app\todo-app\index.ts
create src\app\todo-app\shared\index.ts
Шаблоны и стили также могут быть включены во внутрь файлов скриптов. Angular CLI создаёт несколько отдельных файлов по умолчанию, поэтому, в этой статье, мы будем использовать отдельные файлы.

Давайте начнём с добавления шаблона для компонента в файл src/app/todo-app/todo-app.component.html:

<section class="todoapp">
  <header class="header">
    <h1>Список Дел</h1>

    <input class="new-todo" placeholder="Что должно быть сделано?" autofocus="" [(ngModel)]="newTodo.title" (keyup.enter)="addTodo()">
  </header>

  <section class="main" *ngIf="todos.length > 0">
    <ul class="todo-list">
      <li *ngFor="let todo of todos" [class.completed]="todo.complete">
        <div class="view">
          <input class="toggle" type="checkbox" (click)="toggleTodoComplete(todo)" [checked]="todo.complete">

          <label>{{todo.title}}</label>
          <button class="destroy" (click)="removeTodo(todo)"></button>
        </div>
      </li>
    </ul>
  </section>

  <footer class="footer" *ngIf="todos.length > 0">
    <span class="todo-count">Задач осталось: <strong>{{todos.length}}</strong></span>
  </footer>
</section>

Далее приведено короткое представление Angular синтаксиса для шаблонов, в случае, если вы ещё с ним не сталкивались:

  • [свойство]="выражение": назначить свойству результат выражения
  • (событие)="утверждение": выполнить утверждение, когда произойдёт событие
  • [(свойство)]="выражение": создать двухстороннее связывание с указанным выражением
  • [class.ваш_класс]="выражение": добавить ваш_класс CSS к этому элементу, когда выражение будет истинным
  • [style.color]="выражение": назначить свойство CSS color в зависимости от результата выполнения выражения
Если вам не знаком синтаксис Angular для шаблонов, то необходимо ознакомится с официальной документацией на эту тему.

Давайте посмотрим, что происходит в нашем шаблоне. На самом верху есть поле ввода для создания новой записи:

<input class="new-todo"
       placeholder="Что должно быть сделано?"
       autofocus=""
       [(ngModel)]="newTodo.title"
       (keyup.enter)="addTodo()"
>
  • [(ngModel)]="newTodo.title": добавляет двухстороннее связывание между значением input и newTodo.title
  • (keyup.enter)="addTodo()": говорит Angular, чтобы он выполнил метод addTodo(), когда клавиша Enter была нажата в поле ввода
Не беспокойтесь пока о том, откуда появились newTodo или addTodo() – мы вскоре их рассмотрим более подробно. Просто попытайтесь понять смысл шаблона.

Далее следует секция для вывода записей todo:

<section class="main" *ngIf="todos.length > 0">
  • *ngIf="todos.length > 0": показать элемент section и всё его содержимое, только при условии, что есть хотя бы одна запись todo

Внутри этой секции, мы просим Angular сгенерировать li элементы для каждой записи:

<li *ngFor="let todo of todos" [class.completed]="todo.complete">
  • *ngFor="let todo of todos": в каждой итерации цикла, мы проходимся по записям todos и назначаем конкретную запись в переменную todo
  • [class.completed]="todo.complete": применить класс CSS complete к элементу li, при условии, когда todo.complete является истиной

И наконец, мы отображаем информацию о каждой записи внутри цикла ngFor:

<div class="view">
  <input class="toggle"
         type="checkbox"
         (click)="toggleTodoComplete(todo)"
         [checked]="todo.complete"
  >

  <label>{{todo.title}}</label>
  <button class="destroy" (click)="removeTodo(todo)"></button>
</div>
  • (click)="toggleTodoComplete(todo)": выполнить toggleTodoComplete(todo) при клике на этом чекбоксе
  • [checked]="todo.complete": назначить значение todo.complete свойству checked
  • (click)="removeTodo(todo)": выполнить метод removeTodo(todo), когда была нажата кнопка

Хорошо, теперь давайте вздохнём 🙂 Мы прошлись через довольно-таки большое количество синтаксиса.

Если у вам возникнет желание изучить более подробно синтаксис шаблонов Angular, то отличным вариантом будет начать с официальной документации по шаблонам.

На данный момент, вы могли удивиться – как же выражения addTodo() и newTodo.title могут быть выполнены. Ведь мы ещё не определили их, поэтому, откуда Angular узнает, что они значат?

Это именно то место, где в дело вступает контекст выражения. Контекст выражения компонента является экземпляром компонента. И в свою очередь, экземпляр компонента является экземпляром класса компонента.

Класс компонента нашего TodoAppComponent определён в src/app/todo-app/todo-app.component.ts.

Angular CLI уже создал для нас заготовку класса TodoAppComponent:

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

@Component({
  moduleId: module.id,
  selector: 'app-todo-app',
  templateUrl: 'todo-app.component.html',
  styleUrls: ['todo-app.component.css']
})
export class TodoAppComponent implements OnInit {

  constructor() {}

  ngOnInit() {
  }

}

Таким образом, мы можем немедленно приступить к добавлению нашей логики работы.

Нам понадобится экземпляр TodoService, поэтому, давайте начнём со вставки его в наш компонент.

Первым делом, мы импортируем TodoService класс и определим его в массиве providers декоратора Component:

// Импортируем наш класс, который мы сможем зарегистрировать в качестве зависимости
import { TodoService } from '../todo.service';

@Component({
  // ...
  providers: [ TodoService ]
})
export class TodoAppComponent
{
  // ...
}

В компоненте TodoAppComponent будет произведена вставка зависимости TodoService, таким образом, при необходимости использования этого сервиса будет создан его одиночный экземпляр.

Для системы зависимостей Angular существует множество способов использования. Применённый нами выше синтаксис является укороченной нотацией провайдера класса, таким образом, используется singleton паттерн для работы с зависимостями. Для более детального ознакомления с зависимостями Angular можно рассмотреть документацию на эту тему.

Теперь, когда мы объявили зависимость, можно использовать экземпляр TodoService в конструкторе TodoAppComponent:

// Импортируем наш класс, который мы сможем зарегистрировать в качестве зависимости
import { TodoService } from '../todo.service';

@Component({
  // ...
})
export class TodoAppComponent
{
  // Попросим систему зависимостей Angular вставить нашу зависимость
  // с именем 'TodoService' и назначить её экземпляр свойству 'todoService'
  constructor( private todoService: TodoService ) {}

  // Наш сервис теперь доступен как this.todoService
  toggleTodoComplete( todo )
  {
    this.todoService.toggleTodoComplete(todo);
  }
}

Сейчас мы можем реализовать всю необходимую логику для работы нашего шаблона, добавив свойства и методы в TodoAppComponent класс:

import { Component } from '@angular/core';
import { Todo } from '../todo';
import { TodoService } from '../todo.service';

@Component({
  moduleId: module.id,
  selector: 'app-todo',
  templateUrl: 'todo-app.component.html',
  styleUrls: [ 'todo-app.component.css' ],
  providers: [ TodoService ]
})
export class TodoAppComponent
{
  newTodo: Todo = new Todo();

  constructor( private todoService: TodoService ) {}

  toggleTodoComplete( todo )
  {
    this.todoService.toggleTodoComplete( todo );
  }

  addTodo()
  {
    this.todoService.addTodo( this.newTodo );
    this.newTodo = new Todo();
  }

  removeTodo( todo )
  {
    this.todoService.deleteTodoById( todo.id );
  }

  get todos()
  {
    return this.todoService.getAllTodos();
  }
}

Сначала при инициализации класса компонента, мы назначаем свойству newTodo экземпляр класса Todo с помощью кода new Todo(). Это то самое newTodo, которому мы добавили двухстороннее связывание в шаблоне:

<input class="new-todo"
       placeholder="Что должно быть сделано?"
       autofocus=""
       [(ngModel)]="newTodo.title"
       (keyup.enter)="addTodo()"
>

При изменении значения поля ввода в шаблоне, значение в экземпляре компонента всегда будет обновляться. Так же, как и в случае изменения этого значения в экземпляре компонента, значение поля ввода будет обновлено.

Потом мы реализовали все необходимые методы, которые используются в нашем шаблоне.

Реализация этих методов является очень короткой и легкой для понимания, так как мы поручили обработку всей логики работы сервису todoService.

Делегирование бизнес-логики сервису, является хорошей практикой в программировании и это позволит нам централизованно управлять и тестировать эту логику.

Теперь на осталось сделать пару шагов, чтобы получить готовое приложение.

Последние штрихи

Для начала найдём в нашем проекте файл src/app/angular2-todo-app.component.ts и внесём в него изменения:

import { Component } from '@angular/core';
import { TodoAppComponent } from './todo-app/todo-app.component';

@Component({
  moduleId: module.id,
  selector: 'angular2-todo-app-app',
  templateUrl: 'angular2-todo-app.component.html',
  styleUrls: ['angular2-todo-app.component.css'],
  directives: [ TodoAppComponent ]
})
export class Angular2TodoAppAppComponent {}

Главные изменения состоят в том, что мы импортировали созданный нами компонент TodoAppComponent для вывода записей, и внесли в декоратор Component указание использовать класс TodoAppComponent для обработки директивы app-todo, описанной в этом классе.

Теперь откроем файл src/app/angular2-todo-app.component.html и заменим всё его содержимое на вызов директивы:

<app-todo></app-todo>

И изменим файлы с тестами, код которых можно взять поссылкам: src/app/angular2-todo-app.component.spec.ts и src/app/todo-app/todo-app.component.spec.ts соответственно.

Итак, у нас получилось работающее приложение, правда без стилей.

angular2-crud-cli-06

Добавим предварительно подготовленные стили, которые можно взять по ссылке. И вставим их в файл src/app/todo-app/todo-app.component.css. После сохранения у нас получится полностью готовое и работоспособное приложение.

angular2-crud-cli-07

И до того, как мы закончим этот туториал, давайте попробуем сделать одну интересную вещь с помощью Angular CLI.

Деплой приложения на GitHub Pages

Angular CLI позволяет произвести деплой приложения на GitHub Pages с минимум движений, буквально одной командой.

Для начала нам нужно создать репозиторий на GitHub с именем, которое указано в файле package.json:

"name": "angular2_crud"

Затем выполнить команду:

ng github-pages:deploy --message 'deploy(dist): деплой на GitHub Pages'

Команда github-pages:deploy говорить Angular CLI сделать билд статической версии Angular приложения и выполнить его push в бранч gh-pages нашего GitHub репозитория.

angular2-crud-cli-08

Теперь, созданное нами приложение доступно по адресу: https://sbogdanov108.github.io/angular2_crud/

Просто чудесная возможность для быстрого развёртывания приложения, не правда ли?

Подводя итог…

Angular 2 – крайне мощный инструмент для создания приложения, без всякого сомнения.

В этой статье, мы рассмотрели много разных тем и пришло время подвести краткое резюме тому, что изучили:

  • Мы узнали, как установить Angular CLI и как много времени этот инструмент может сохранить для нас, при создании нового приложения или добавление функционала к существующему
  • Мы изучили, как реализовать бизнес-логику в сервисах Angular и как произвести тестирование этой логики используя юнит-тесты
  • Как использовать компоненты для взаимодействия с пользователем и каким образом делегировать логику работы сервису, используя вставку зависимостей
  • Мы изучили основы синтаксиса шаблонов Angular и немного коснулись темы работы зависимостей в Angular
  • И под конец, мы узнали, как можно быстро развернуть наше приложение на GitHub Pages

Осталось много того, о чём ещё хотелось бы поговорить, но это уже темы для следующих статей:

  • Взаимодействие с REST API бэкэндом, используя Angular 2 HTTP сервис
  • Фильтрация записей todo с помощью Angular pipes
  • Реализация навигации для создания многостраничного приложения

И ещё много другого…

Исходные коды приложения доступны в GitHub репозитории по ссылке.

При создании статьи были использованы следующие источники:

  1. Angular 2 Tutorial: Create a CRUD App with Angular CLI
  2. Angular CLI Docs
  3. Angular 2 Docs
  4. Jasmine Docs
Поделиться

12 комментариев

Владимир На скринах, судя по кнопкам окон Ubuntu? Что за редактор используете и какие плагины для Angular TypeScript??
Альберт Спасибо за статью. Но при повторении на последней версии Angular многое не работает как задумывалось. Что-то удалось поправить, а что-то нет. Я пока новичок. Можно ли надеяться что будет вторая версия на github с исправлениями для последней версии Angular ?
Алексей Добрый день с помощью angular-cli создал новый проект для тестирования работы модуля router, при работе с "включенной" командой ng serve приложение работает по необходимому сценарию, т.е. при загрузке главной страницы получаем общий контент и контент главной страницы, при загрузке страницы второго уровня вложенности получаем загрузку необходимого контента вместо контента главной страницы. Но после команды ng build и после того, как скопировал содержимое папки dist при переходе на хостинг работает только главная страница, при попытке зайти на другую страницу, хостинг выдает сообщение об ошибке, о том, что такая страница не существует. Код практически и не писал сгененировал 2 компонента командами ng generate component и добавил роутер из документации. Добавил сейчас содержимое папки dist на сайт testapp.m2m-sib.ru. Так же видно что приложение работает нормально здесь: https://shurygin.github.io/m2m-sib/
Сергей Богданов Алексей, я вам на форуме geekbrains ответил. Надеюсь, поможет. Может кому-то еще это будет полезно: нужно в корневую директорию на хостинге, где находятся файлы из папки dist создать файл .htaccess и в него закинут этот код.
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>
Игорь Да, нормальный стартовый пакет, 308 мб и 40831 файл, не знаю что ангуларовцы туда впихнули, но одно точно- все остальные фрейвморки тихо курят в сторонке. И как это развернуть на хостинге?Кроме как на ноде не работает
Илья Все нужные пакеты выкачиваются только один раз в начале разработки веб-приложения. Они нужны только для компиляции в js. После команды ng build в папке dist будет только 2 мегабайта (index.html, js-файлы), которые можно залить на любой хостинг.
Роман Огромное Вам спасибо за статью!!! Почти всё очень ясно и понятно)) Хотел узнать, будет ли продолжение: Взаимодействие с REST API бэкэндом, используя Angular 2 HTTP сервис Фильтрация записей todo с помощью Angular pipes Реализация навигации для создания многостраничного приложения Спасибо!
Сергей Богданов Рад, что вам была полезна статья! С удовольствием бы сделал продолжение, но банально нет свободного времени.
Антон не поленился, скопировал скрипты. получилось почти 1.5Мб!! JS кода?!?!.. для того, чтобы запилить todo??!
Сергей Богданов На самом деле, ангуляр вообще не обязательно использовать, т.к. есть одни фреймворк, называется VanillaJS, который гораздо более популярен - его используют Facebook, Google,YouTube, Wikipedia, Twitter, Microsoft и т.д. Он работает быстрее ангуляря, и самое главное, весит в запакованном состоянии всего лишь 25 байт! Да, именно 25 байт! А в распакованном состоянии всего лишь 0 байт. Скачать его можно по ссылке http://vanilla-js.com/ :)
Ярослав Ну ти і підколов :), я потратив з пів години поки дойшло :)

Оставить комментарий

Вы можете использовать следующие HTML-теги:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Обязательно к заполнению