1
votes

I am new to DOM manipulation in Angular 2. I am trying to modify a sibling element on the basis of attribute value on an element.

e.g. Adding asterisk (star) symbol on label, if input contains required attribute.

I am having a directive, which can access attributes, & form control on input field. Now I would like to modify sibling label from within this directive.

I am aware of nativeElement & Renderer2 basics, but unable to find proper way of accessing & modifying sibling.

<div class="form-group">
    <label for="email">Email address:</label>
    <input type="email" class="form-control" id="email" required validate>
  </div>

in my validate directive I would like to check if required attribute is available on input, & if yes I would like to add a class on sibling element i.e. label.

I can access input element using ElementRef inside directive, but how to access & modify label or any other neighboring elements, i.e. child, parent, sibling.

Any reference document for such basic operations will be a great help.

2
You can use @ViewChild and @ContentChild bindings to find a ElementRef using a #templateName in the template. If you share some example code that would help give a formal answer. - Reactgular
Updated the question. I am aware about accessing element using ElementRef . I want to get control over sibling dom element using this i.e. I want functionality simillar to Jquery prev() function.. - Rahul Bhooteshwar
What is the problem with it? There is previousElementSibling if you want to use jquery.prev - yurzui
Can you add the code of your validate directive? - yurzui
@yurzui Thanks for the reply, previousElementSibling worked for me. Also got to know that every HTML property will be accessible on nativeElement. - Rahul Bhooteshwar

2 Answers

0
votes

About the required attribute you could add it in your input directive selector like this:

@Directive({
  selector: 'input[required]'
})

For the <label> logic I would try with JS in constructor:

constructor(elementRef:ElementRef){
  let element = elementRef.nativeElement;
  this.label = element.parentElement.querySelector('label[for="'+'element.id+'"]');
  \\ Now you can use this.label.classList to manage its classes

And I'm also sorry that I didn't find another way to do that the "angular" way !

0
votes

It is important to understand what is it ElementRef in your directive. Put a console.log(this.el).

I have an example with a form with dynamic fields and user can toggle some information under input.

<div class="owner-bu-toggle">
   <input .../>
   <i class="fa facaret-left" owner-bu-toggle></i>
</div>

<div class="table-container d-none">
 my table -> default hidden will be here
</div>

And the directive it looks like this:

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

@Directive({
    selector: '[owner-bu-toggle]'
})
export class OwnerBuToggleDirective {
    tableContainer: HTMLElement;
    isVisible = false;

    constructor(private el: ElementRef) {}

    ngAfterViewInit() {

        this.tableContainer = this.el.nativeElement.parentElement.nextElementSibling;

    }

    @HostListener('click') 

    onClickToggle(): void {

        this.isVisible = !this.isVisible;

        this.tableContainer.className = this.isVisible ? 'd-block table-container' : 'd-none table-container';

        this.el.nativeElement.className = this.isVisible ? 'fa fa-caret-down' : 'fa fa-caret-left';

    }
}

You can also use document.querySelector in ngAfterViewInit hook, but is better elementref to work with every instance of directive.