Как я могу привязать к вводу директивы из другой директивы? - PullRequest
0 голосов
/ 08 мая 2019

Я пытаюсь немного упростить мой шаблонный процесс, сжимая пару проверочных входов в директиву, которую я могу поместить в элемент <input>, который нуждается в них.

Введенный ввод будет выглядеть так:

<input [(ngModel)]='options.org_name' required id="org_name" type="text" nbInput fullWidth
                placeholder="What is your organization called?"
                [appValidating]='this'
                minlength="3" maxlength="40" />

, где моя директива [appValidating].Код для appValidating таков:

@Directive({
  selector: '[appValidating]'
})
export class ValidatingDirective {

  @Input('appValidating') validator: IValidatingComponent;
  @Input() id: string;

  @HostBinding('status')
  get status() {
    return this.validator.validity[this.id] === true ? null : 'danger';
  }

  @HostListener('input', ['$event'])
  onInput(event: any) {
    this.validator.checkValidity(this.id, event);
  }

  constructor() { }

}

Моя проблема в том, что он не позволяет мне использовать @HostBinding для 'status', который является входом директивы nbInput, которая также находится в элементе.

Uncaught (in promise): Error: Template parse errors: Can't bind to 'status' since it isn't a known property of 'input'.

Есть ли хороший способ для меня связать ввод этой директивы из моей директивы?

1 Ответ

1 голос
/ 08 мая 2019

Во-первых, вы можете установить атрибут с помощью HostBinding, но в итоге это не сработает для того, что вам нужно

@HostBinding('attr.status') // this will set an attribute on the element

причина, по которой это не будет работать для вас, заключается в том, что вы не устанавливаете атрибут с угловым определением, поэтому он не имеет возможности привязываться к @Input директивы nbInput.

Я немного подумал об этом, попробовал несколько решений проблемы и, наконец, остановился на этом, но, по общему признанию, для его работы может потребоваться доступ и возможность изменять обе директивы.

Первая директива

@Directive({
    selector: '[firstDirective]',
})
export class FirstDirective {
    @Input('status') private status: boolean;

    @HostListener('click', ['$event'])
    public onHostClicked(event: MouseEvent): void {
        event.preventDefault();
        event.stopImmediatePropagation();
        event.stopPropagation();
        console.log('first directive: ', this.status);
    }
}

первая директива получает статус Input, и onClick элемента host выводит статус

Вторая директива

@Directive({
    selector: '[secondDirective]',
})
export class SecondDirective {
    @Input('status') private status = false;
    @Output('statusChange') private statusChangeEvent = new EventEmitter(
        this.status,
    ); // an output event named as attributeNameChange is how you tell a two way bound attribute that it's value has changed

    @HostListener('click', ['$event'])
    public onHostClicked(event: MouseEvent): void {
        event.preventDefault();
        event.stopImmediatePropagation();
        event.stopPropagation();

        this.status = !this.status; // toggle the boolean
        this.statusChangeEvent.emit(this.status); // emit that it changed
    }

вторая директива принимает входной статус и генерирует выходной сигнал statusChange, а onClick элемента host отображает значение состояния и изменяет его.

Компонент

@Component({
    template: '<button firstDirective secondDirective [(status)]="status">Change Status</button>',
})
export class Component {
    status = true; // the value in the implementing component that is being toggled
    constructor() {}
}

Итак, в приведенном выше примере происходит то, что в компоненте реализации установлено значение, к которому могут обращаться обе директивы, и оно действует как сквозной переход между двумя из них. Всякий раз, когда вторая директива видит щелчок, она переворачивает логическое состояние, и первая директива видит это изменение.

...