Angular2 não pode ser vinculado a DIRECTIVE, pois não é uma propriedade conhecida do elemento

92

Eu gerei um novo @Directive pelo Angular CLI, ele foi importado para o meu app.module.ts

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

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

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

e tento usar no meu componente (ChatWindowComponent)

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

mesmo se dentro da diretiva for apenas o código angular CLI gerado:

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

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

 constructor() { }

 }

Eu entendi o erro:

zone.js: 388 Rejeição de promessa não tratada: Erros de análise de modelo: Não é possível vincular a 'appContenteditableModel', pois não é uma propriedade conhecida de 'p'.

Eu tentei quase todas as mudanças possíveis, seguindo esta documentação angular tudo deveria funcionar, mas não funciona.

Qualquer ajuda?

Tomas Javurek
fonte
O resultado que preciso está [(appContenteditableModel)]="draftMessage.text"no final ...
Tomas Javurek
Então tente assim<p [appContenteditableModel]="draftMessage.text"></p>
Sanket
Funciona sem colchetes appContenteditableModel="draftMessage.text"e também (appContenteditableMode)l="draftMessage.text"resolve a rejeição de promessa, mas também parece não passar a variável
Tomas Javurek

Respostas:

149

Ao envolver uma propriedade entre colchetes, []você está tentando vinculá-la. Portanto, você deve declará-lo como um @Input.

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

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

  @Input()
  appContenteditableModel: string;

  constructor() { }

}

A parte importante é que o membro ( appContenteditableModel) precisa ser nomeado como a propriedade no nó DOM (e, neste caso, o seletor de diretiva).

naeramarth7
fonte
Eu tenho entrada @Input ('appContenteditableModel') model : any;e saída @Output ('appContenteditableModel') update : EventEmitter<any> = new EventEmitter();na minha diretiva. Parece que o modelo funciona bem, mas o emissor chamado por this.update.emit(value)não altera o valor do componente pai. O que eu faço de errado? [(appContenteditableModel)]="draftMessage.text"
Tomas Javurek
Na verdade, eu tento "simular" [(ngModel)] fora do elemento <input>
Tomas Javurek
@Outputserve apenas para emitir eventos. Se você deseja manter o valor sincronizado com o valor do pai, considere adicionar a @HostBindinganotação.
naeramarth7 de
Se eu entender bem @HostBindingajudará a manter o valor em sincronia dentro do elemento html, estou certo? Este elemento preciso ser editado pelo usuário contenteditable="true"para que a entrada que eu preciso manter em sincronia com a variável no mesmo componente.
Tomas Javurek de
35

Se você estiver usando um módulo compartilhado para definir a diretiva, certifique-se de que ela seja declarada e exportada pelo módulo em que foi definida.

// this is the SHARED module, where you're defining directives to use elsewhere
@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [NgIfEmptyDirective, SmartImageDirective],
  exports: [NgIfEmptyDirective, SmartImageDirective]
})
Simon_Weaver
fonte
e se eles não estiverem no mesmo módulo?
Ohad Sadan de
@OhadSadan Não sei exatamente o que você quer dizer. Este é um exemplo de quando você não os tem no mesmo módulo, e estou apenas dizendo que certifique-se de declarar E exportar as diretivas se você estiver criando-os em um módulo compartilhado (que você deve então importá-los para um módulo diferente).
Simon_Weaver
Em seu módulo 'principal' você só precisa importar o 'módulo de diretivas' e então todos os seus componentes podem vê-los.
Simon_Weaver de
Este é um detalhe minucioso, mas muitas vezes esquecido. Obrigado !
Sami
2

Para mim, a correção foi mover as referências da directiva de raiz app.module.ts(as linhas para import, declarationse / ou exports) para o módulo mais específica src/subapp/subapp.module.tsmeu componente pertencia.

SushiGuy
fonte
2

Eu estava enfrentando o mesmo problema com uma diretiva declarada em um módulo compartilhado. Estou usando esta diretiva para desabilitar um controle de formulário.

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 funcionar corretamente, declare e exporte a diretiva no módulo compartilhado (ou qualquer módulo que você estiver usando).

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

Agora podemos usar esta diretiva em qualquer módulo onde estivermos importando SharedModule .

Agora, para desativar o controle de uma forma reativa, podemos usá-lo assim:

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

Erro eu estava fazendo isso, estava usando apenas o seletor (appDisableControl) e passando o parâmetro de desativação para este. mas para passar um parâmetro de entrada, temos que usá-lo como acima.

ImFarhad
fonte
1

Em suma, como sua diretiva se parece com uma diretiva âncora , remova os colchetes e ela funcionaria.

Na verdade, não encontrei as seções correspondentes relacionadas a quando os colchetes devem ser removidos ou não, onde apenas uma menção que encontrei está localizada na seção sobre componentes dinâmicos :

Aplique isso <ng-template> sem os colchetes

, que, no entanto, não está perfeitamente coberto no documento de Diretivas de Atributos .

Individualmente, concordo com você e estava pensando que [appContenteditableModel]deveria ser igual a appContenteditableModele o analisador de modelo angular também pode solucionar se há @input()vinculação de dados ou não automaticamente. Mas eles parecem exatamente não processados ​​igualmente sob o capô, mesmo na versão Angular atual do 7.

千 木 郷
fonte