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?


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).


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]
})

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.


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.


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.