Angular2 Impossible de se lier à DIRECTIVE car ce n'est pas une propriété connue de l'élément

92

J'ai généré une nouvelle @Directive par Angular CLI, elle a été importée dans mon app.module.ts

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

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

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

et j'essaye d'utiliser dans mon composant (ChatWindowComponent)

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

même si la directive contient uniquement du code généré par CLI angulaire:

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

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

 constructor() { }

 }

J'ai eu l'erreur:

zone.js: 388 Rejet de promesses non gérées: Erreurs d'analyse de modèle: Impossible de se lier à 'appContenteditableModel' car ce n'est pas une propriété connue de 'p'.

J'ai essayé presque tous les changements possibles, en suivant cette documentation angulaire, tout devrait fonctionner, mais ce n'est pas le cas.

De l'aide?

Tomas Javurek
la source
Le résultat dont j'ai besoin est [(appContenteditableModel)]="draftMessage.text"à la fin ...
Tomas Javurek
Alors essayez comme ça<p [appContenteditableModel]="draftMessage.text"></p>
Sanket
Cela fonctionne sans parenthèses appContenteditableModel="draftMessage.text"et (appContenteditableMode)l="draftMessage.text"résout également le rejet de la promesse, mais il semble également ne pas passer la variable
Tomas Javurek

Réponses:

147

Lorsque vous encapsulez une propriété entre crochets, []vous essayez de vous y lier. Vous devez donc le déclarer comme un fichier @Input.

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

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

  @Input()
  appContenteditableModel: string;

  constructor() { }

}

La partie importante est que le membre ( appContenteditableModel) doit être nommé comme propriété sur le nœud DOM (et, dans ce cas, le sélecteur de directive).

naeramarth7
la source
J'ai une entrée @Input ('appContenteditableModel') model : any;et une sortie @Output ('appContenteditableModel') update : EventEmitter<any> = new EventEmitter();dans ma directive. Il semble que le modèle fonctionne bien mais l'émetteur appelé par this.update.emit(value)ne change pas la valeur du composant parent. Ce que je fais mal? [(appContenteditableModel)]="draftMessage.text"
Tomas Javurek
En fait, j'essaye de "simuler" [(ngModel)] en dehors de l'élément <input>
Tomas Javurek
@Outputest pour l'émission d'événements uniquement. Si vous souhaitez garder la valeur synchronisée avec celle du parent, vous pouvez envisager d'ajouter l' @HostBindingannotation.
naeramarth7
Si je comprends bien, @HostBindingcela aidera à garder la valeur synchronisée dans l'élément html, ai-je raison? Cet élément doit être modifié par l'utilisateur contenteditable="true"pour que l'entrée soit synchronisée avec la variable du même composant.
Tomas Javurek
35

Si vous utilisez un module partagé pour définir la directive, assurez-vous qu'elle est à la fois déclarée et exportée par le module dans lequel elle est définie.

// this is the SHARED module, where you're defining directives to use elsewhere
@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [NgIfEmptyDirective, SmartImageDirective],
  exports: [NgIfEmptyDirective, SmartImageDirective]
})
Simon_Weaver
la source
et que faire s'ils ne sont pas dans le même module?
Ohad Sadan
@OhadSadan Je ne sais pas exactement ce que vous voulez dire. Ceci est un exemple de cas où vous ne les avez pas dans le même module, et je dis simplement assurez-vous de déclarer ET exporter les directives si vous les créez dans un module partagé (que vous devez ensuite importer dans un module différent).
Simon_Weaver
Dans votre module «principal», il vous suffit d'importer le «module de directives» pour que tous vos composants puissent les voir.
Simon_Weaver
C'est un détail minutieux mais souvent manqué. Merci !
Sami
2

Pour moi , le correctif se déplaçait les références directive de la racine app.module.ts(les lignes pour import, declarationset / ou exports) au module plus spécifique src/subapp/subapp.module.tsmon composant appartenait.

SushiGuy
la source
1

En résumé, comme votre directive ressemble à une directive d'ancrage , supprimez les crochets et cela fonctionnerait.

En fait, je n'ai pas trouvé les sections correspondantes liées au moment où les crochets doivent être supprimés ou non, où une seule mention que j'ai trouvée se trouve dans la section sur les composants dynamiques :

Appliquer cela <ng-template> sans les crochets

, qui n'est cependant pas parfaitement couvert dans les directives d'attributs document des .

Individuellement, je suis d'accord avec vous et je pensais que cela [appContenteditableModel]devrait être égal à appContenteditableModelet que l'analyseur de modèle angulaire pourrait également contourner le fait qu'il y ait @input()une liaison de données ou non automatiquement. Mais ils semblent ne pas être traités de la même manière sous le capot, même dans la version angulaire actuelle de 7.

千 木 郷
la source
1

J'étais confronté au même problème avec une directive déclarée dans un module partagé. J'utilise cette directive pour désactiver un contrôle de formulaire.

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

}

Pour le faire fonctionner correctement, déclarez et exportez la directive dans le module partagé (ou dans tout module que vous utilisez).

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

Nous pouvons maintenant utiliser cette directive dans n'importe quel module où nous importons SharedModule .

Maintenant, pour désactiver le contrôle d'un formulaire réactif, nous pouvons l'utiliser comme ceci:

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

Erreur que je faisais, j'utilisais uniquement le sélecteur (appDisableControl) et en passant le paramètre de désactivation à cela. mais pour passer un paramètre d'entrée, nous devons l'utiliser comme ci-dessus.

ImFarhad
la source