3

I have a template that creates a list of links using *ngFor and a separate div element that I want to change its location based on the currently active link.

Template:

<div #divHandle
    *ngFor="let link of links; let i = index"
    class="div-link"
    (click)="changeActiveLink(i)">
    <h2>{{link}}</h2>
</div>
<div
[@indexState]="activeLink"
id="highlighter"></div>

This results in a structure like so:

<div class="div-link">
  <div (click)="changeActiveLink(0)"><h2>Link 1</h2></div>
  <div (click)="changeActiveLink(1)"><h2>Link 2</h2></div>
  <div (click)="changeActiveLink(2)"><h2>Longer link 1</h2></div>
  <div (click)="changeActiveLink(3)"><h2>Longer link 2</h2></div>
</div>
<div id="highlighter"></div>

I want my highlighter div to get the width of Link 1 when activeLink = 0. Similar to this plain js:

var High = document.getElementById('highlighter');
High.style.width = document.getElementsByClass('div-link')[0].children[activeLink].offsetWidth; //activeLink = 0

In my app.component.ts file:

import { Component, AfterViewInit, ViewChildren, Directive, QueryList, ElementRef} from '@angular/core';

@Directive({selector: '[class~=div-link]'})
@Directive({selector: '.div-link'}) // variant
@Directive({selector: '#divHandle'}) // variant
@Directive({selector: '[divHandle]'}) // variant
export class ChildDirective {
    constructor(elem: ElementRef){}
}

@Component({
    selector: 'my-app',
    ...
})
export class AppComponent implements AfterViewInit {
    @ViewChildren(ChildDirective) childrenContent: QueryList<ChildDirective>;

    ngAfterViewInit(){
        console.log(this.childrenContent);
    }
}

When I log the childrenContent I get a QueryList object, but it is empty, no elements to get info from.

I have tried several @Directive selectors and always my QueryList is empty.

1
  • hey dude did u see my answer? Commented Mar 5, 2017 at 5:48

2 Answers 2

4
+50

You can use the $event property to handle the width, height, offset and so on. By using this method, a traditional javascript comes into play as below

HTML code will be as

<div *ngFor="let link of links;" class="div-link" 
             height="100px"
             width="30px"
             (click)="changeActiveLink($event)">
          <h2>{{link}}</h2>
</div>
<div height="height" width="width" id="highlighter">some text</div>

Handling the clicked element from above div element as

changeActiveLink(value){
    this.height=value.srcElement.parentElement.attributes['height'].value;
    this.width=value.srcElement.parentElement.attributes['width'].value;
    console.log(this.width);
    console.log(this.height); 
  }

Note: In the above example, the click event is on the letter so we will get the srcElement as h2 so I am using the parentElement. In real time you can handle it with either ways having a if condition inside the method.

You can also console.log the clicked element and get more idea to achieve this.

LIVE DEMO

Sign up to request clarification or add additional context in comments.

5 Comments

This does not seem to work, I can pass the event, and I am able to get value.srcElement which is <h2>link</h2>, and value.srcElement.parentElement which will be the <div></div> but I cannot get attributes['width'] that is undefined, and .value() fails as well.
you need the height and width of the clicked div element ?
Correct, clicking on the div (click)=changeActiveLink() should get the clicked div's width and offsetLeft, which should be used to animate the highlighter div's width and offsetLeft.
did u see console.log() in that plunker? have a reference at this post. Still if you need some clarity tell me I will explain
Yea, it works in plunker, however, you set a fixed width on the links, mine does not have that, each word is a different length and makes the div's have different widths as a result. If I had them all a fixed width, I could just change the highlights value based of a multiple of the index.
0

You can place a handle on the element you want to mess with ..

<div #handle ..>

then in your component class you can access the component using the @ViewChild annotation.

Then in your ngOnViewInit you can do ..

ngOnViewInit() {
  viewChildEl.offsetLeft = 100;
}

Should point you in the right direction.

2 Comments

I am already using animation to manage the look of myhighlighter div, but I do not know how to get the width of the list of div's created by the *ngFor, the @ViewChild appears to be for a single element. I need something more like getElementsByClass to get an array of elements. So I can get the width of a child of this array using the activeLink which is the currently active index, 0, 1, 2, 3,....
You can use ViewChildren() but you need to add #handle to every element you want to receive. ViewChild(ren) can only query for template variable names or component/directive types. You can create a directive with a class selector that injects ElementRef to get all elements using ViewChildren for a class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.