Неизвестный элемент — Angular 2 с материалом Angular 2

В этот момент бьюсь головой о стену. Я получаю сообщение об ошибке при запуске приложения angular 2 с использованием SystemJS и углового материала, не могу понять, почему. Я использую проект angular-seed: https://github.com/mgechev/angular-seed. Я добавил материал с помощью этого руководства: https://github.com/mgechev/angular-seed/wiki/Integration-with-AngularMaterial2.

Ошибка:

Unhandled Promise rejection: Template parse errors: 'md-toolbar' is not a known element:

home.component.html

<md-toolbar>Test</md-toolbar>

Конфигурация SystemJS

this.NPM_DEPENDENCIES = [ ...this.NPM_DEPENDENCIES, {src: '@angular/material/core/theming/prebuilt/indigo-pink.css', inject: true} // {src: 'jquery/dist/jquery.min.js', inject: 'libs'}, // {src: 'lodash/lodash.min.js', inject: 'libs'}, ]; this.addPackageBundles({ name:'@angular/material', path:'node_modules/@angular/material/bundles/material.umd.js', packageMeta:{ main: 'index.js', defaultExtension: 'js' } });

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

Модуль приложения

...
import { MaterialModule } from '@angular/material';

@NgModule({
  imports: [BrowserModule, HttpModule, MaterialModule.forRoot(), AppRoutingModule, AboutModule, HomeModule, SharedModule.forRoot()],
  ...

package.json

  "dependencies": {
    "@angular/common": "~2.4.0",
    "@angular/compiler": "~2.4.0",
    "@angular/core": "~2.4.0",
    "@angular/forms": "~2.4.0",
    "@angular/http": "~2.4.0",
    "@angular/material": "^2.0.0-beta.2",
    "@angular/platform-browser": "~2.4.0",
    "@angular/platform-browser-dynamic": "~2.4.0",
    "@angular/router": "~3.4.1",
    "core-js": "^2.4.1",
    "intl": "^1.2.5",
    "rxjs": "~5.0.3",
    "systemjs": "0.19.41",
    "zone.js": "^0.7.4"
  }
  ...

Главный компонент

import { Component, OnInit } from '@angular/core';
import { NameListService } from '../shared/name-list/name-list.service';

/**
 * This class represents the lazy loaded HomeComponent.
 */
@Component({
  moduleId: module.id,
  selector: 'sd-home',
  templateUrl: 'home.component.html',
  styleUrls: ['home.component.css'],
})
export class HomeComponent implements OnInit {
...

Вопрос. Как исправить проблему с неизвестным элементом? Спасибо!


person karns    schedule 25.02.2017    source источник
comment
Проверьте внутри package.json свою версию материала.   -  person kind user    schedule 25.02.2017
comment
импортируйте только MaterialModule вместо MaterialModule.forRoot() и проверьте.   -  person micronyks    schedule 25.02.2017
comment
@Kinduser - добавлен package.json для вас.   -  person karns    schedule 25.02.2017
comment
@micronyks - это не исправляет и не меняет ошибку, спасибо.   -  person karns    schedule 25.02.2017
comment
какие ошибки вы получаете?   -  person Aravind    schedule 25.02.2017
comment
объявлен ли HomeComponent внутри HomeModule?   -  person snorkpete    schedule 06.03.2017


Ответы (3)


Как сказано в последней версии (2.0.0-beta.3 цезиевый головоногий (2017 г.) -04-07)) необходимо импортировать MdToolbarModule в модуль, загружающий home.component.

Если модуль home.module, просто загрузите туда MdToolbarModule, вот так:

import { MdToolbarModule } from '@angular/material';

@NgModule({
    imports: [
        ...
        MdToolbarModule, // HERE YOU IMPORT THE TOOLBAR MODULE. IF YOU WANT ONLY THIS MODULE IN YOUR BUILD
        ...
],
...

Это необходимо из-за AOT и Lazy Load. Это единственный способ, которым Angular может удалить ненужный код. Если вы не загрузите модуль в каждый модуль, который в этом нуждается, компилятор никогда не узнает, кто его использует, и ему нужно будет добавить его во все компоненты, даже если это не ленивый компонент.

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

Таким образом, если вы загружаете модуль в app.module с помощью forRoot(), это означает, что вы создали глобальный экземпляр модуля services, и все дочерние компоненты будут иметь доступ к этим службам. По этой причине вам не нужно снова загружать material.module в home.module, потому что MaterialModule используется для загрузки сервисов, используемых Material для соединения компонентов материала. Это все, что делает MaterialModule.

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

Для модулей, загруженных без forRoot(), у вас не будет одноэлементных служб, поэтому вам нужно будет загрузить их в каждый компонент. Все это необходимо для лучшей тряски дерева, когда у вас есть только то, что вам нужно в вашей сборке.

person Bruno João    schedule 06.03.2017
comment
ДОХ! Конечно, это что-то настолько очевидное. Ценю, что вы заглянули в это. Это было действительно потому, что исходный проект, который я использовал, имел эти отдельные модули... не могли бы вы сформулировать, почему они решили поместить каждый компонент в отдельный модуль? - person karns; 07.03.2017
comment
Для меня отдельные модули — это внутренняя деталь реализации Angular Material. В какой-то момент они рекомендовали вам импортировать отдельные модули, которые вы используете, но с переходом на лучшую поддержку встряхивания дерева они теперь указывают MaterialModule как модуль, который вы должны импортировать. - person snorkpete; 07.03.2017
comment
@vinagreti, я не думаю, что ваши комментарии верны. Ему НУЖНО импортировать MaterialModule в HomeModule, независимо от того, импортировал ли он его уже в AppModule. И поскольку импорт MaterialModule уже существует, импорт MdToolbarModule становится избыточным. - person snorkpete; 07.03.2017
comment
@Snorkpete Я обновил ответ, добавив более подробную информацию. - person Bruno João; 07.03.2017
comment
@vinagreti, вы правы насчет сервисов — когда вы импортируете MaterialModule в AppModule, его сервисы становятся доступными из корневого инжектора, что в основном означает, что вы можете использовать сервисы MaterialModule из любого места. Однако то же самое НЕ относится к декларируемым (компоненты, директивы, каналы, т.е. то, что вы используете в своих шаблонах). Для декларируемых материалов MaterialModule вы должны импортировать их в КАЖДЫЙ модуль, который вы их используете (или, опять же, импортировать другой модуль, который экспортирует MaterialModule) - person snorkpete; 07.03.2017
comment
B@Snorkpete Я обновил ответ, добавив более подробную информацию. А вот насчет избыточности ваше утверждение неверно. Все дело в ленивой загрузке. MaterialModule — это клей для своих компонентов. Это не компонент и не модуль для всех компонентов. Это просто набор сервисов, используемых модулями материала. Вам придется загружать модули в каждый модуль, который в этом нуждается. Это единственный способ, которым Angular может узнать, нужен ли лениво загруженному модулю какой-то другой модуль (в данном случае mdToolbarModule), чтобы вставить его в лениво загруженный модуль. - person Bruno João; 07.03.2017
comment
@Snorkpete, я не нашел документов об этом, но для меня я загружаю только MaterialModule в app.module, а в дочерних я загружаю только компонентный модуль как mdInputModule mdIconModule. И AOT работает как шарм. Вы можете быть правы, когда говорите, что нам нужно загрузиться, но вариант использования не доказывает вашу точку зрения. - person Bruno João; 07.03.2017
comment
@vinagreti, в том же примере попробуйте импортировать MaterialModule (вместо MdInputModule) в дочерний компонент, и вы получите точно такое же поведение. Дело в том, что вам нужно импортировать модуль, содержащий компоненты, которые вы хотите использовать в каждом модуле, в котором вы хотите их использовать. Импортируете ли вы их, импортируя MaterialModule или импортируя отдельные модули (MdInputModule, MdToolbarModule и т. д.), несколько произвольный. Но если у вас есть функциональный модуль, недостаточно просто импортировать MaterialModule в AppModule и покончить с этим. Вы также должны импортировать в свой функциональный модуль - person snorkpete; 07.03.2017
comment
Давайте продолжим обсуждение в чате. - person Bruno João; 07.03.2017

@karns, вы упомянули, что проблема существует в HomeComponent, и я заметил, что в вашем списке импорта есть HomeModule.

Принадлежит ли HomeComponent этому HomeModule?

Если да, то импортировали ли вы MaterialModule в свой HomeModule?

Вам необходимо импортировать MaterialModule (или модуль, который экспортирует MaterialModule) в каждый модуль, который может использовать компоненты Angular Material в своих шаблонах.

person snorkpete    schedule 06.03.2017
comment
Спасибо за ответ, Снорк. Это правильно, однако я приму ответ Винагрети, поскольку у него есть пример кода. Проголосовал. - person karns; 07.03.2017

Опция 1 :

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

    npm install --save @angular/material
    
  2. Перейдите в node_modules и проверьте, присутствуют ли эти файлы.

    node_modules/@angular/material/bundles/material.umd.js
    @angular/material/core/theming/prebuilt/indigo-pink.css
    
  3. Если есть два вышеуказанных файла,

    • Delete the materials folder
    • Установите его снова
    • Перед установкой проверьте, есть ли он в качестве зависимости в файле package.json.
    • Проверьте сейчас, присутствуют ли указанные выше файлы.
  4. На вкладке сети инструментов разработчика убедитесь, что у вас есть, как показано ниже

введите здесь описание изображения

Вариант 2:

Если вышеуказанное решение не сработало, попробуйте это

  1. Включите указанные ниже файлы в index.html введите здесь описание изображения
  2. В файле config.js удалите строку @angular/material и используйте указанную ниже ссылку cdn.

    '@angular/material': 'https://unpkg.com/@angular/material/bundles/material.umd.js',

ЖИВАЯ ДЕМО, чтобы показать, что ссылка cdn работает

Обновление 1: Плункер теперь работает нормально, вы можете посмотреть на него.

Объяснение для варианта 2 заключается в использовании ссылки cdn, которой не важно, установлен ли у вас node_module или нет, в большинстве случаев это определенно сработает. Если эта ссылка cdn решит вашу проблему. update me Мы попробуем исправить вариант 1 в вашем случае.

person Aravind    schedule 25.02.2017
comment
К сожалению вариант 1 не сработал. Файлы есть и все равно ошибки. Не могли бы вы уточнить вариант 2 пули № 2, пожалуйста? Я предполагаю, что вы имеете в виду конфигурацию SystemJS. Не могли бы вы предоставить контекст для изменения кода? - person karns; 27.02.2017
comment
@karns посмотрит на это и сообщит вам через некоторое время. - person Aravind; 28.02.2017
comment
Спасибо за помощь, Aravind - очень ценю изучение этого, и у вас есть несколько полезных предложений, которые в конечном итоге сузили проблему, но не решили ее. Однако другие ответили правильно. - person karns; 07.03.2017