Angular2 Nie można powiązać z DIRECTIVE, ponieważ nie jest to znana właściwość elementu

92

Wygenerowałem nową @Directive przez Angular CLI, zaimportowałem ją do mojego app.module.ts

import { ContenteditableModelDirective } from './directives/contenteditable-model.directive';

import { ChatWindowComponent } from './chat-window/chat-window.component';

@NgModule({
  declarations: [
    AppComponent,
    ContenteditableModelDirective,
    ChatWindowComponent,
    ...
  ],
  imports: [
    ...
  ],
  ...
})

i próbuję użyć w moim komponencie (ChatWindowComponent)

<p [appContenteditableModel] >
    Write message
</p>

nawet jeśli wewnątrz dyrektywy jest tylko kod wygenerowany przez Angular CLI:

 import { Directive } from '@angular/core';

 @Directive({
   selector: '[appContenteditableModel]'
 })
 export class ContenteditableModelDirective {

 constructor() { }

 }

Wyskoczył mi błąd:

zone.js: 388 Nieobsłużone odrzucenie obietnicy: Błędy analizy szablonu: Nie można powiązać z „appContenteditableModel”, ponieważ nie jest to znana właściwość „p”.

Próbowałem prawie wszystkich możliwych zmian, po tej kątowej dokumentacji wszystko powinno działać, ale tak nie jest.

Jakaś pomoc?

Tomas Javurek
źródło
Wynik, którego potrzebuję, jest [(appContenteditableModel)]="draftMessage.text"na końcu ...
Tomas Javurek
Spróbuj w ten sposób<p [appContenteditableModel]="draftMessage.text"></p>
Sanket
Działa bez nawiasów, appContenteditableModel="draftMessage.text"a także (appContenteditableMode)l="draftMessage.text"rozwiązuje problem odrzucenia obietnicy, ale też wydaje się, że nie przekazuje zmiennej
Tomas Javurek

Odpowiedzi:

147

Kiedy zawijasz właściwość w nawiasy [], próbujesz się z nią wiązać. Musisz więc zadeklarować to jako plik @Input.

import { Directive, Input } from '@angular/core';

@Directive({
 selector: '[appContenteditableModel]'
})
export class ContenteditableModelDirective {

  @Input()
  appContenteditableModel: string;

  constructor() { }

}

Ważną częścią jest to, że member ( appContenteditableModel) musi zostać nazwany jako właściwość w węźle DOM (iw tym przypadku selektor dyrektywy).

naeramarth7
źródło
Mam dane wejściowe @Input ('appContenteditableModel') model : any;i wyjściowe @Output ('appContenteditableModel') update : EventEmitter<any> = new EventEmitter();w mojej dyrektywie. Wygląda na to, że model działa dobrze, ale emiter wywołany przez this.update.emit(value)nie zmienia wartości w komponencie macierzystym. Co robię źle? [(appContenteditableModel)]="draftMessage.text"
Tomas Javurek
Właściwie to próbuję "zasymulować" [(ngModel)] poza elementem <input>
Tomas Javurek
@Outputsłuży wyłącznie do emitowania wydarzeń. Jeśli chcesz zachować synchronizację wartości z wartością rodzica, możesz rozważyć dodanie @HostBindingadnotacji.
naeramarth7
Jeśli dobrze rozumiem @HostBinding, pomoże to w utrzymaniu synchronizacji wartości w elemencie HTML, czy mam rację? Ten element musi być edytowany przez użytkownika contenteditable="true", aby dane wejściowe były zsynchronizowane ze zmienną w tym samym komponencie.
Tomas Javurek
35

Jeśli używasz modułu udostępnionego do zdefiniowania dyrektywy, upewnij się, że jest on zadeklarowany i wyeksportowany przez moduł, w którym jest zdefiniowany.

// this is the SHARED module, where you're defining directives to use elsewhere
@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [NgIfEmptyDirective, SmartImageDirective],
  exports: [NgIfEmptyDirective, SmartImageDirective]
})
Simon_Weaver
źródło
a co jeśli nie są w tym samym module?
Ohad Sadan
@OhadSadan Nie jestem pewien, co dokładnie masz na myśli. To jest przykład sytuacji, gdy nie masz ich w tym samym module, a ja mówię tylko, że zadeklaruj i wyeksportuj dyrektywy, jeśli tworzysz je w module współdzielonym (który musisz następnie zaimportować do inny moduł).
Simon_Weaver
W swoim „głównym” module wystarczy zaimportować „moduł dyrektyw”, a wszystkie komponenty będą mogły je zobaczyć.
Simon_Weaver
Jest to drobiazg, ale często pomijany. Dziękuję Ci !
Sami
2

Dla mnie poprawka poruszał dyrektywy referencje od korzenia app.module.ts(dla linii import, declarationsi / lub exports) do bardziej konkretnego modułu src/subapp/subapp.module.tsmój składnik należy.

SushiGuy
źródło
1

Podsumowując, ponieważ twoja dyrektywa wygląda jak dyrektywa kotwicy , usuń nawiasy i zadziała.

Właściwie nie znalazłem odpowiednich sekcji związanych z tym, kiedy nawiasy powinny zostać usunięte lub nie, gdzie tylko jedna wzmianka, którą znalazłem, znajduje się w sekcji o komponentach dynamicznych :

Zastosuj to <ng-template> bez nawiasów kwadratowych

, co jednak nie zostało w pełni ujęte w dokumencie dyrektyw dotyczących atrybutów .

Indywidualnie zgadzam się z tobą i myślałem, że [appContenteditableModel]powinno to być równe, appContenteditableModela kątowy parser szablonów może również obejść, czy istnieje @input()powiązanie danych, czy też nie automatycznie. Ale wydaje się, że nie są przetwarzane równo pod maską, nawet w obecnej wersji Angular 7.

千 木 郷
źródło
1

Miałem ten sam problem z dyrektywą zadeklarowaną w module współdzielonym. Używam tej dyrektywy, aby wyłączyć formant formularza.

import { Directive, Input } from '@angular/core';
import { NgControl } from '@angular/forms';

@Directive({
  selector: '[appDisableControl]'
})
export class DisableControlDirective {

  constructor(private ngControl: NgControl) { }

  @Input('disableControl') set disableControl( condition: boolean) {
    const action = condition ? 'disable' : 'enable';
    this.ngControl.control[action]();
  }

}

Aby to działało poprawnie, zadeklaruj i wyeksportuj dyrektywę w module współdzielonym (lub dowolnym module, którego używasz).

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DisableControlDirective } from './directives/disable-control/disable-control.directive';

@NgModule({
  declarations: [
    DisableControlDirective
  ],
  imports: [
    CommonModule
  ],
  exports: [DisableControlDirective],
  providers: [],
  bootstrap: []
})
export class SharedModule { }

Teraz możemy użyć tej dyrektywy w dowolnym module, do którego importujemy SharedModule .

Teraz, aby wyłączyć kontrolkę formularza reaktywnego, możemy jej użyć w następujący sposób:

<input type="text" class="form-control" name="userName" formControlName="userName" appDisableControl [disableControl]="disable" />

Błąd robiłem to, użyłem tylko selektora (appDisableControl) i przekazałem do tego parametr wyłączenia. ale aby przekazać parametr wejściowy, musimy użyć go jak powyżej.

ImFarhad
źródło