Angular2 no se puede enlazar a DIRECTIVE ya que no es una propiedad conocida del elemento

92

Genere un nuevo @Directive por Angular CLI, lo importé a mi app.module.ts

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

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

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

y trato de usar en mi componente (ChatWindowComponent)

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

incluso si dentro de la directiva es solo código generado por CLI angular:

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

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

 constructor() { }

 }

Me sale el error:

zone.js: 388 Rechazo de promesa no controlada: Errores de análisis de plantilla: no se puede vincular a 'appContenteditableModel' porque no es una propiedad conocida de 'p'.

Probé casi todos los cambios posibles, siguiendo estos documentos angulares, todo debería funcionar, pero no es así.

¿Alguna ayuda?

Tomas Javurek
fuente
El resultado que necesito es [(appContenteditableModel)]="draftMessage.text"al final ...
Tomas Javurek
Entonces intente así<p [appContenteditableModel]="draftMessage.text"></p>
Sanket
Funciona sin paréntesis appContenteditableModel="draftMessage.text"y también (appContenteditableMode)l="draftMessage.text"resuelve el rechazo de la promesa, pero tampoco parece pasar la variable
Tomas Javurek

Respuestas:

147

Al envolver una propiedad entre corchetes [], intenta vincularla. Entonces tienes que declararlo como @Input.

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

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

  @Input()
  appContenteditableModel: string;

  constructor() { }

}

La parte importante es que el miembro ( appContenteditableModel) necesita ser nombrado como la propiedad en el nodo DOM (y, en este caso, el selector de directivas).

naeramarth7
fuente
Tengo entrada @Input ('appContenteditableModel') model : any;y salida @Output ('appContenteditableModel') update : EventEmitter<any> = new EventEmitter();en mi directiva. Parece que el modelo funciona bien, pero el emisor llamado por this.update.emit(value)no cambia el valor en el componente principal. ¿Qué hice mal? [(appContenteditableModel)]="draftMessage.text"
Tomas Javurek
En realidad, trato de "simular" [(ngModel)] fuera del elemento <input>
Tomas Javurek
@Outputes solo para emitir eventos. Si desea mantener el valor sincronizado con el de los padres, puede considerar agregar la @HostBindinganotación.
naeramarth7
Si entiendo bien @HostBinding, ayudaré a mantener el valor sincronizado dentro del elemento html, ¿estoy en lo cierto? Necesito que el usuario edite este elemento contenteditable="true"para que la entrada deba mantenerse sincronizada con la variable en el mismo componente.
Tomas Javurek
35

Si está utilizando un módulo compartido para definir la directiva, asegúrese de que sea declarado y exportado por el módulo en el que está definido.

// this is the SHARED module, where you're defining directives to use elsewhere
@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [NgIfEmptyDirective, SmartImageDirective],
  exports: [NgIfEmptyDirective, SmartImageDirective]
})
Simon_Weaver
fuente
¿y si no están en el mismo módulo?
Ohad Sadan
@OhadSadan No estoy seguro de a qué te refieres exactamente. Este es un ejemplo de cuando no los tiene en el mismo módulo, y solo digo que se asegure de declarar Y exportar directivas si las está creando en un módulo compartido (que luego debe importarlas a un módulo diferente).
Simon_Weaver
En su módulo 'principal' solo necesita importar el 'módulo de directivas' y luego todos sus componentes pueden verlos.
Simon_Weaver
Este es un detalle minucioso pero a menudo se pierde. Gracias !
Sami
2

Para mí, la solución se movía referencias de la Directiva de la raíz app.module.ts(para las líneas import, declarationsy / o exports) al módulo más específico src/subapp/subapp.module.tsmi componente pertenecía.

SushiGuy
fuente
1

En resumen, debido a que su directiva parece una directiva de anclaje , elimine los corchetes y funcionaría.

En realidad, no he encontrado las secciones correspondientes relacionadas con cuándo deben eliminarse los corchetes o no, donde solo una mención que encontré se encuentra en la sección de componentes dinámicos :

Aplicar eso <ng-template> sin los corchetes

, que sin embargo no está perfectamente cubierto en las Directivas de atributos documento de .

Individualmente, estoy de acuerdo con usted y estaba pensando que [appContenteditableModel]debería ser igual a, appContenteditableModely el analizador de plantilla angular también podría solucionar si hay @input()enlace de datos o no automáticamente. Pero parecen exactamente no procesados ​​igualmente bajo el capó, incluso en la Versión Angular actual de 7.

千 木 郷
fuente
1

Estaba enfrentando el mismo problema con una directiva declarada en un módulo compartido. Estoy usando esta directiva para deshabilitar un control de formulario.

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

}

Para que funcione correctamente, declare y exporte la directiva en un módulo compartido (o cualquier módulo que esté utilizando).

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

Ahora podemos usar esta directiva en cualquier módulo donde estemos importando SharedModule .

Ahora, para deshabilitar el control de un formulario reactivo, podemos usarlo así:

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

Error: lo estaba haciendo, estaba usando solo el selector (appDisableControl) y pasando el parámetro de desactivación a esto. pero para pasar un parámetro de entrada, tenemos que usarlo como arriba.

ImFarhad
fuente