21

I'm trying to implement a custom directive in Angular 2 for moving an arbitrary HTML element around. So far everything is working except that I don't now how to get the initial position of the HTML element when I click on it and want to start moving. I'm binding to the top and left styles of my HTML element with those two host bindings:

/** current Y position of the native element. */
@HostBinding('style.top.px') public positionTop: number;

/** current X position of the native element. */
@HostBinding('style.left.px') protected positionLeft: number;

The problem is that both of them are undefined at the beginning. I can only update the values which will also update the HTML element but I cannot read it? Is that suppose to be that way? And if yes what alternative do I have to retrieve the current position of the HTML element.

tzwickl
  • 1,263
  • 1
  • 15
  • 31

4 Answers4

32
<div (click)="move()">xxx</div>
// get the host element
constructor(elRef:ElementRef) {}

move(ref: ElementRef) {
  console.log(this.elRef.nativeElement.offsetLeft);
}

See also https://stackoverflow.com/a/39149560/217408

Community
  • 1
  • 1
Günter Zöchbauer
  • 558,509
  • 191
  • 1,911
  • 1,506
  • But offset doesn't give me the relative position of the element? – tzwickl Mar 03 '17 at 10:50
  • Your question doesn't say anything about "relative". `offsetLeft` is just an example. The rest is the same as in plain JavaScript, this is why I added the link to my answer. – Günter Zöchbauer Mar 03 '17 at 10:51
  • 2
    a snippet of code + a link to another answer (that has only a snippet of code and a link) should not be up-voted, I think. – Marco Altieri Mar 30 '18 at 13:26
  • This solution does not work. Clicking on a button in a mat-toolbar, returns the element of the toolbar instead of the button. See https://stackoverflow.com/questions/36006894/angular2-get-clicked-element-id – Marco Altieri Mar 30 '18 at 13:52
  • 4
    @MarcoAltieri thanks for downvoting. I don't see how your comment is related to my answer. – Günter Zöchbauer Mar 30 '18 at 13:56
  • @GünterZöchbauer I implemented what you have suggested and the ElementRef that I receive is not the clicked element. Unfortunately, if you do not add some comments together with the code, it is difficult to know if I am using your suggestion correctly. – Marco Altieri Mar 30 '18 at 14:01
  • @GünterZöchbauer I can see now that is the browser that is returning the wrong element (in the event object). Probably something related with how the toolbar is implemented. – Marco Altieri Mar 30 '18 at 14:14
  • The ExternalRef object is the event.target object. This is not always what you need because it can be the parent container (as it is in my case). What I want is the event.currentTarget that is the element on which the listener is attached. – Marco Altieri Mar 30 '18 at 14:32
27

In typeScript you can get the position as follows:

@ViewChild('ElementRefName') element: ElementRef;

const {x, y} = this.element.nativeElement.getBoundingClientRect();
  • This solution won't work when the browser is not at 100% size – Loc Truong Oct 31 '19 at 05:05
  • 4
    What will work when the browser is not at 100% size? – SoEzPz Jun 22 '20 at 03:53
  • `@ViewChild('ElementRefName') element: ElementRef;` is an error now in Angular 13: error TS2564: Property 'element' has no initializer and is not definitely assigned in the constructor. – b264 May 06 '22 at 07:03
10

in html:

<div (click)="getPosition($event)">xxx</div>

in typescript:

getPosition(event){
    let offsetLeft = 0;
    let offsetTop = 0;

    let el = event.srcElement;

    while(el){
        offsetLeft += el.offsetLeft;
        offsetTop += el.offsetTop;
        el = el.parentElement;
    }
    return { offsetTop:offsetTop , offsetLeft:offsetLeft }
}
mohammad ali
  • 109
  • 1
  • 5
  • 4
    Testing this in an Angular app now and it's giving odd values (very high numbers). I don't believe a child's offset is the simple aggregation of all of it's parents offsets. I believe the correct property is offsetParent. – Rohan May 28 '19 at 03:04
  • 2
    @Rohan Yes, I'm using offsetParent instead of parentElement and it appears to be working. – C.M. Jul 01 '20 at 16:09
-1

You can use two way

// html

<div id="section" ></div>

// 1)

@ViewChild('section', { static: false }) public section?: ElementRef;

this.section.nativeElement.scrollIntoView({ behavior: "smooth", block: "start" });

// 2)

document.getElementById("section").scrollIntoView({ behavior: "smooth", block: "center" });