Angular2 Kann nicht an DIRECTIVE gebunden werden, da es keine bekannte Eigenschaft des Elements ist

88

Ich habe neues @Directive von Angular CLI generiert und es wurde in meine app.module.ts importiert

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

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

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

und ich versuche, in meiner Komponente (ChatWindowComponent) zu verwenden

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

Auch wenn innerhalb der Direktive nur Angular CLI-Code generiert wird:

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

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

 constructor() { }

 }

Ich habe den Fehler bekommen:

zone.js: 388 Nicht behandelte Ablehnung von Versprechungen: Fehler beim Analysieren von Vorlagen: Kann nicht an 'appContenteditableModel' gebunden werden, da dies keine bekannte Eigenschaft von 'p' ist.

Ich habe fast alle möglichen Änderungen ausprobiert. Nach diesen eckigen Dokumenten sollte alles funktionieren, aber es funktioniert nicht.

Irgendeine Hilfe?

Tomas Javurek
quelle
Das Ergebnis, das ich brauche, ist [(appContenteditableModel)]="draftMessage.text"am Ende ...
Tomas Javurek
Dann versuchen Sie es so<p [appContenteditableModel]="draftMessage.text"></p>
Sanket
Es funktioniert ohne Klammern appContenteditableModel="draftMessage.text"und (appContenteditableMode)l="draftMessage.text"löst auch die Ablehnung des Versprechens, aber es scheint auch die Variable nicht zu übergeben
Tomas Javurek

Antworten:

139

Wenn Sie eine Eigenschaft in Klammern setzen [], versuchen Sie, sie zu binden. Sie müssen es also als deklarieren @Input.

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

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

  @Input()
  appContenteditableModel: string;

  constructor() { }

}

Der wichtige Teil ist, dass member ( appContenteditableModel) als Eigenschaft auf dem DOM-Knoten (und in diesem Fall als Direktivenselektor) benannt werden muss.

naeramarth7
quelle
Ich habe Eingabe @Input ('appContenteditableModel') model : any;und auch Ausgabe @Output ('appContenteditableModel') update : EventEmitter<any> = new EventEmitter();in meiner Direktive. Es scheint, dass das Modell gut funktioniert, aber der von aufgerufene Emitter this.update.emit(value)ändert den Wert in der übergeordneten Komponente nicht. Was ich falsch mache? [(appContenteditableModel)]="draftMessage.text"
Tomas Javurek
Eigentlich versuche ich, [(ngModel)] außerhalb des <input> -Elements zu "simulieren"
Tomas Javurek
@Outputdient nur zum Aussenden von Ereignissen. Wenn Sie den Wert mit dem Wert des übergeordneten Elements synchron halten möchten, können Sie die @HostBindingAnmerkung hinzufügen .
Naeramarth7
Wenn ich gut verstehe und dabei @HostBindinghelfe, den Wert innerhalb des HTML-Elements synchron zu halten, habe ich Recht? Dieses Element muss vom Benutzer bearbeitet werden, contenteditable="true"damit die Eingabe mit der Variablen in derselben Komponente synchron bleibt.
Tomas Javurek
34

Wenn Sie ein gemeinsam genutztes Modul zum Definieren der Direktive verwenden, stellen Sie sicher, dass es von dem Modul, in dem es definiert ist, deklariert und exportiert wird.

// this is the SHARED module, where you're defining directives to use elsewhere
@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [NgIfEmptyDirective, SmartImageDirective],
  exports: [NgIfEmptyDirective, SmartImageDirective]
})
Simon_Weaver
quelle
und was ist, wenn sie nicht im selben Modul sind?
Ohad Sadan
@OhadSadan Ich bin mir nicht sicher, was du genau meinst. Dies ist ein Beispiel dafür, wenn Sie sie nicht im selben Modul haben, und ich sage nur, stellen Sie sicher, dass Sie Anweisungen deklarieren UND exportieren, wenn Sie sie in einem gemeinsam genutzten Modul erstellen (das Sie dann in ein Modul importieren müssen) anderes Modul).
Simon_Weaver
In Ihrem 'Haupt'-Modul müssen Sie nur das' Direktiven-Modul 'importieren, und dann können alle Ihre Komponenten sie sehen.
Simon_Weaver
Dies ist ein winziges Detail, das jedoch häufig übersehen wird. Danke !
Sami
2

Für mich war die Update Bezugnahme auf die Richtlinie von der Wurzel zu bewegen app.module.ts(die Leitungen für import, declarationsund / oder exports) den spezielleren Modulsrc/subapp/subapp.module.ts meiner Komponente gehörte.

SushiGuy
quelle
1

In der Summe, weil Ihre Direktive wie eine Anker-Direktive aussieht , entfernen Sie die Klammern und es würde funktionieren.

Tatsächlich habe ich die entsprechenden Abschnitte nicht gefunden, die sich darauf beziehen, wann die Klammern entfernt werden sollen oder nicht, wobei sich nur eine Erwähnung im Abschnitt über dynamische Komponenten befindet :

Wenden Sie das <ng-template> ohne die eckigen Klammern an

, was jedoch im Dokument Attributrichtlinien nicht perfekt behandelt wird .

Individuell stimme ich Ihnen zu und war der Meinung, dass der Parser [appContenteditableModel]für appContenteditableModeleckige Vorlagen gleich sein sollte, um zu umgehen, ob @input()Daten automatisch gebunden werden oder nicht. Aber sie scheinen unter der Haube nicht gleich verarbeitet zu sein, selbst in der aktuellen Angular-Version von 7.

千 木 郷
quelle
1

Ich hatte das gleiche Problem mit einer Direktive, die in einem gemeinsam genutzten Modul deklariert wurde. Ich verwende diese Anweisung, um ein Formularsteuerelement zu deaktivieren.

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

}

Um es richtig zu machen, deklarieren und exportieren Sie die Direktive in einem gemeinsam genutzten Modul (oder einem beliebigen Modul, das Sie verwenden).

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 { }

Jetzt können wir diese Direktive in jedem Modul verwenden, in das wir SharedModule importieren .

Um die Steuerung einer reaktiven Form zu deaktivieren, können wir sie folgendermaßen verwenden:

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

Fehler Ich habe es getan, ich habe nur den Selektor (appDisableControl) verwendet und den Deaktivierungsparameter an diesen übergeben. Um einen Eingabeparameter zu übergeben, müssen wir ihn wie oben verwenden.

ImFarhad
quelle