Просто хочу сказать, что я признаю, что есть много сообщений SO, связанных с ошибками "Не удается связать с X, поскольку это не известное свойство Y".Я просмотрел тонну из них и нашел ряд ответов, которые решают конкретные проблемы, но у меня возникли проблемы с переводом на мой случай, который, на самом деле, я считаю довольно общим и связан с фундаментальным неправильным пониманиемкак я должен решать свой вариант использования.
Я создаю приложение Angular (7), которое я разделил на components
и routes
.components
- это модульные элементы (выпадающие списки, модалы, кнопки и т. Д.), А маршруты - это отдельные страницы в приложении.Термин немного запутанный, потому что оба являются технически угловатыми компонентами.Другими словами, структура (в пределах src/
) выглядит следующим образом:
- app
- components
- dropdown
- dropdown.component.ts
- dropdown.component.html
- dropdown.component.scss
- dropdown.component.spec.ts
- routes
- library
- library.component.ts
- library.component.html
- library.component.scss
- library.component.spec.ts
...
Итак, у меня есть маршрут к библиотеке, который является просто угловым компонентом, который импортирует компонент Dropdown и выглядит следующим образом:
import { Component, OnInit } from '@angular/core';
import { DropdownComponent } from '../../components/dropdown/dropdown.component';
@Component({
selector: 'app-library',
templateUrl: './library.component.html',
styleUrls: ['./library.component.scss']
})
export class LibraryComponent implements OnInit {
pickItem($event) {
console.log($event.item, $event.index);
}
constructor() { }
ngOnInit() {}
}
Соответствующий HTML-файл библиотеки:
<div class="library row py4">
<h3 class="typ--geo-bold typ--caps mb5">Style Library</h3>
<div class="mb4" style="max-width: 35rem;">
<p class="typ--geo-bold typ--caps">Dropdowns</p>
<app-dropdown
[items]="['One', 'Two', 'Three']"
(pick)="pickItem($event)"
title="Default dropdown"
></app-dropdown>
<br />
<app-dropdown
[items]="['One', 'Two', 'Three']"
(pick)="pickItem($event)"
title="Inline dropdown"
class="dropdown--inline"
></app-dropdown>
</div>
</div>
Компонент раскрывающегося списка является базовым компонентом, имеющим аналогичную структуру.Я не буду вставлять это здесь, если не спросят, потому что я не уверен, что это будет добавка.(Достаточно сказать, что принимает items
в качестве входных данных - относится к приведенной ниже ошибке).
Это прекрасно работает в браузере и корректно создается в рабочей среде.
Когда я запускаю тест library.components.spec.ts
, я сталкиваюсь со следующей ошибкой:
Failed: Template parse errors:
Can't bind to 'items' since it isn't a known property of 'app-dropdown'.
1. If 'app-dropdown' is an Angular component and it has 'items' input, then verify that it is part of this module.
2. If 'app-dropdown' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("
<p class="typ--geo-bold typ--caps">Dropdowns</p>
<app-dropdown
[ERROR ->][items]="['One', 'Two', 'Three']"
(pick)="pickItem($event)"
title="Default dropdown"
Вот базовый файл спецификации библиотеки:
import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { LibraryComponent } from './library.component';
describe('LibraryComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [LibraryComponent],
}).compileComponents();
}));
it('should create the component', () => {
const fixture = TestBed.createComponent(LibraryComponent);
const lib = fixture.debugElement.componentInstance;
expect(lib).toBeTruthy();
});
});
Ни то, ни другоеКомпонент Library или компонент Dropdown имеют связанные модули.Насколько я понимаю, эта ошибка может быть связана с тем, что я не импортировал компонент Dropdown в модуль Library или что-то еще, но
- A) Я неконечно, как это сделать,
- B) Тогда я не уверен, как включить этот модуль в приложение в целом, и
- C) Я не уверен, какова ценность этого, кроме как заставить тест работать.
Есть ли способ заставить тест работать без преобразования этих компонентов в модули?Должны ли все компоненты маршрута быть модулями?
РЕДАКТИРОВАТЬ
Добавление выпадающего компонента, если необходимо:
<div
class="dropdown"
[ngClass]="{ open: open }"
tab-index="-1"
[class]="class"
#dropdown
>
<div class="dropdown__toggle" (click)="onTitleClick(dropdown)">
<span class="dropdown__title">{{ finalTitle() }}</span>
<span class="dropdown__icon icon-arrow-down"></span>
</div>
<div *ngIf="open" class="dropdown__menu">
<ul>
<li
*ngFor="let item of items; let ind = index"
class="dropdown__item"
[ngClass]="{ selected: selectedIndex === ind }"
(click)="onItemClick(dropdown, item, ind)"
>
<span class="dropdown__label">{{ item }}</span>
</li>
</ul>
</div>
</div>
И:
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-dropdown',
templateUrl: './dropdown.component.html',
styleUrls: ['./dropdown.component.scss']
})
export class DropdownComponent implements OnInit {
@Input() items: Array<string>;
@Input() public selectedIndex: number = null;
@Input() public title = 'Select one';
@Input() public open = false;
@Input() public class = '';
@Output() pick = new EventEmitter();
constructor() { }
ngOnInit() {}
finalTitle () {
return typeof this.selectedIndex === 'number'
? this.items[this.selectedIndex]
: this.title;
}
onItemClick(dropdown, item, index) {
this._blur(dropdown);
this.selectedIndex = index;
this.open = false;
this.pick.emit({ item, index });
}
onTitleClick(dropdown) {
this._blur(dropdown);
this.open = !this.open;
}
_blur(dropdown) {
if (dropdown && dropdown.blur) { dropdown.blur(); }
}
}