> For the complete documentation index, see [llms.txt](https://eigenspace.gitbook.io/dev-standards/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://eigenspace.gitbook.io/dev-standards/angular.md).

# Angular

## 0. Введение

### 0.1. Термины и определения

### 0.2. Использованные источники

1. [AngularJs Naming](http://bguiz.github.io/js-standards/angularjs/naming/)

## 1. Правила именования файлов

### 1.1. Типы файлов

Допустимо использовать следующие типы (в терминологии, используемой в п.1.1), определяющие категорию, к которой относится класс:

1. service - сервис;
2. module - модуль;
3. controller - контроллер;
4. component - компонент;
5. filter/pipe - фильтр;
6. directive - директива;
7. routes - маршрутизация (url'ы приложения)
8. config - конфигурация.

```
    // Плохо
    tag-service.js
    tag-controller.js
    tag-component.js
    format-date-filter.js
    dashboard-directive.js
    app-routes.js
    app-module.js
    app-config.js

    // Хорошо
    tag.service.js
    tag.controller.js
    tag.component.js
    format-date.filter.js
    dashboard.directive.js
    app.routes.js
    app.module.js
    app.config.js
```

## 2. Форматирование

### 2.1. Классы

#### 2.1.1. Порядок полей

В дополнение к общему правилу, определяющему порядок полей в файлах на языке [typescript](https://github.com/eigen-space/codestyle/tree/c8afb079ad9300b695d5d7cfc8409b59548c3028/docs/dev/guidelines/guidelines_web_typescript/README.md), необходимо придерживаться следующего порядка размещения полей:

1. `@Input`
2. `@Output`
3. `@ViewChild` / `@ViewChildren`
4. `@ContenChild` / `@ContenChildren`
5. Остальные поля в группе полей (например, другие публичные поля)

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

```typescript
    class SomeComponent {
        @Input() prop1;
        @Input() prop2;

        @Output() emitter1;
        @Output() emitter2;

        @ViewChild('content') content;
        @ViewChildren('button') buttons;

        @ContentChild(PopupComponent) popup;
        @ContentChildren(AttributeBaseComponent) attributes;

        // ... other public fields

        // ... other private fields
    }
```

#### 2.1.2. Порядок размещения методов жизненного цикла angular-компонентов

Методы жизненного цикла angular-компонентов должны предшествовать других методам в рамках их группы. Например, реализуя интерфейс `OnInit`, мы должны реализовать публичный метод `ngOnInit()`. Соответственно в группе публичных методов он должен предшествовать другим методам. Методы же жизненного цикла должны быть расположены сверху вниз в порядке прохождения [жизненного цикла](https://angular.io/guide/lifecycle-hooks), начиная от инициализации и заканчивая разрушением компонента:

```typescript
    class SomeComponent {

        // ...

        ngOnChanges() {}

        ngOnInit() {}

        ngDoCheck() {}

        ngAfterContentInit() {}

        ngAfterContentChecked() {}

        ngAfterViewInit() {}

        ngAfterViewChecked() {}

        ngOnDestroy() {}

        // ... other public methods
    }
```

#### 2.1.3. Порядок аннотаций @Input

Аннотация `@Input` проставляется на getter, если он есть, в ином случае на setter, если он есть. Если же свойство объявлено через публичное поле, то `@Input` проставляется на это поле.

```typescript
    class SomeClass {

        // Плохо
        get someProp() {}

        @Input()
        set someProp(value) {}

        // Хорошо
        @Input()
        get someProp() {}

        set someProp(value) {}
    }
```

#### 2.1.4. Поля с аннтотациями

Поля с аннотациями, например `@Input`, всегда записываем в одну строку, не оставляя аннотацию на отдельной строке. Это относится и к аннотациям типа `@ContentChildren`, и к аннотациями `@Input('someSelector')` с параметрами внутри. Если аннотация превышает установленный лимит на длину строки (см. [Общие стандарты web-разработки, 3.1. Длина строк](https://github.com/eigen-space/codestyle/tree/c8afb079ad9300b695d5d7cfc8409b59548c3028/docs/dev/guidelines/guidelines_web_common?id=_31-Длина-строк/README.md)), то она должна разбиваться на две строки: аннотация и поле, которому она принадлежит.

```typescript
    class SomeClass {
        // Плохо

        @Input()
        someProp1;

        @Input('someProp2Alias')
        someProp2;

        @ContentChildren(ResourceListRowComponent) 
        items = new QueryList<ResourceListRowComponent>();

        @ContentChildren(forwardRef(() => CheckboxComponent), { descendants: true }) checkboxes: QueryList<CheckboxComponent>;

        // Хорошо

        @Input() someProp1; 
        @Input('someProp2Alias') someProp2Alias;

        @ContentChildren(ResourceListRowComponent) items = new QueryList<ResourceListRowComponent>();

        @ContentChildren(forwardRef(() => CheckboxComponent), { descendants: true }) 
        checkboxes: QueryList<CheckboxComponent>;
    }
```

#### 2.1.5. Аксессоры (get/set) и методы с аннотациями

Аннотации для аксессоров (get/set) и методов записываются всегда на отдельной строке.

```typescript
    class SomeClass {
        // Плохо

        @HostListener('document:keydown.escape') onEscPressed() {
            this.close();
        }

        @Input() get title(): string {
            return this._title;
        }

        // Хорошо

        @HostListener('document:keydown.escape') 
        onEscPressed() {
            this.close();
        }

        @Input() 
        get title(): string {
            return this._title;
        }
    }
```

#### 2.1.6. Поля с аннтотациями @ViewChild, @ViewChildren, @ContentChild, @ContentChildren

Поля с аннотациями `@ViewChild, @ViewChildren, @ContentChild, @ContentChildren` всегда объявляем публичными. Пришли к такому варианту, т.к. в этом случае без особо ущерба получаем:

* больше возможностей и удобств при написании спецификаций на компоненты;
* лучшую читаемость этих полей с точки зрения чтения кода;
* более однородно с точки зрения работы с angular, т.к. все поля и методы, что мы хотим использовать в шаблоне

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

  с шаблона компонента.

В этом случае решили пренебречь инкапсуляцией этих полей.

```typescript
    class SomeClass {
        // Плохо
        @ContentChildren(ResourceListRowComponent)
        private items = new QueryList<ResourceListRowComponent>();

        // Хорошо
        @ContentChildren(ResourceListRowComponent) items = new QueryList<ResourceListRowComponent>();
    }
```

#### 2.1.7. Порядок полей в аннтотациях директив и компонентов

Придерживаться следующего порядка полей в аннотациях директив и компонентов:

```
@Component / @Directive ({
    selector,
    templateUrl,
    styleUrls / styles,
    providers,
    encapsulation,
    changeDetection
})
```

### 2.2. Шаблоны

#### 2.2.1. Порядок атрибутов

**2.2.1.1. Порядок групп (типов) атрибутов**

Размещать группы (типы) атрибутов в следующем порядке: 1. Директивы (`*ngFor`) 2. Ссылки (`#tab`) 3. Атрибуты без значений (`content-tab`) 4. Двунаправленные атрибуты (`[(value)]='value'`) 5. Атрибуты-входы (`[id]='groupId'`) 5. Входящие атрибуты 5. Исходящие атрибуты

```
   vrt-component-example(
        *ngFor='let tab of tabs',
        #tab,
        content-tab,
        [(value)]='value',
        [id]='groupId',
        [title]='groupTitle'
        [hasBorder]='true',
        placeholder='IDS_SOME_PLACEHOLDER',
        (click)='onSelectTab(tab)'
   )
```

**2.2.1.2. Порядок атрибутов внутри групп**

Придерживаться порядка атрибутов внутри каждой группы по правилу: от более важного к менее неважному. При этом внутри группы придерживаться порядка атрибутов: [Шаблоны (Html, Pug), 2.2. Порядок атрибутов](https://github.com/eigen-space/codestyle/tree/c8afb079ad9300b695d5d7cfc8409b59548c3028/docs/dev/guidelines/guidelines_web_templates?id=_22-Порядок-атрибутов/README.md)

```
   vrt-component-example(
        [id]='groupId',
        [title]='groupTitle'
        [hasBorder]='true'
   )
```

#### 2.2.2. Отступы

**2.2.2.1. Внутри интерполяции ()**

Не должно быть отступов внутри фигурных скобок интерполяции в шаблонах:

```
    // Плохо
    {{ item.title }}

    // Хорошо
    {{item.title}}
```

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

## 3. Правила именования

### 3.1. Общие

### 3.2. Поля с аннотациями

#### 3.2.1. Поля с аннтотациями @ViewChild, @ViewChildren и переменные шаблона

Если для получения DOM-элемента с шаблона используется `@ViewChild`/`@ViewChildren`, а также переменная шаблона `#<templatVariable>`, то следует избегать совпадения названия переменной класса-компонента и переменной шаблона, что может приводить к проблемам со значением этих переменных при использовании в шаблоне.

Для этого следует:

1. Переменную в шаблоне называть с суффиксом `El`, т.е. `<elementName>El`, например `popupEl`:

```
    +b.popup(#popupEl)
```

1. В компоненте переменную называть без суффиксов и префиксов по имени элемента `<elementName>`:

```typescript
    @ViewChild('popupEl') popup: ElementRef;
```

### 3.3. Выходы компонентов (Output, Emitter)

Инициатор события именуется в формате: `<...существительные><глагол настоящего времени>`.

Обработчик события же называется в виде `on<...существительные><глагол в прошедшем времени>`, если название обработчика является парой для события: `(click) -> onClicked(), (select) -> onItemSelected()`, или в виде семантически значимого действия `<глагол [+ существвительное, описывающие действие]>` (в квадратных скобках указана необязательная часть): `close(), finalizeTrip(), ...`.

```
vrt-popup((categorySelect)='onCategorySelected($event)')
vrt-dropdown-menu-item-attribute((actionPerform)='finalizeTrip(entity, $event)')
```

## 4. Директивы

### 4.1. `[ngClass]`, `[class.*]`

1. Предпочтительно использовать `[class.*]`, где это возможно. По сути это относится ко

   всем классам, названия которых не вычисляются. Например,

```
    // Плохо
    vrt-main-panel([title]='"План"', [ngClass]='{ "main-panel--size_sm": minimized, "main-panel--size_lg": !minimized }')

    // Хорошо
    vrt-main-panel([title]='"План"', [class.main-panel--size_sm]='minimized', [class.main-panel--size_lg]='!minimized')
```

1. `[ngClass]` использовать только в тех случаях, когда присваиваемый класс вычисляется. Например, вычисляется его

   имя или набор классов.

```
    +b.BUTTON.btn(#btn,
                  [ngClass]="[" +
                    "'btn--state_' + state, " +
                    "'btn--size_' + size, " +
                    "'btn--type_' + type, " +
                    "'btn--order_' + order, " +
                    "'btn--mode_' + mode" +
                  "]")
```

## 5. TODO

1. Стиль для написания с использованием angular: компоненты, сервисы.

   Какие файлы создаются?

   Как называются?
2. Названия файлов (для контроллеров, сервисов, сущностей, перечислений)
3. Angular функция или чистый javascript&#x20;
4. Использование `@ng-inject`
5. В шаблонах должно быть минимум логики.
6. В шаблонах не переносить атрибуты на новую строку, если они помещаются в лимит по строке
7. Ловить зависимости в конструкторе через переменные в правильном регистре.
8. Присваивать зависимости в приватные поля класса.
9. Добавить про именование классов


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://eigenspace.gitbook.io/dev-standards/angular.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
