Skip to main content

Get incorrect offsetWidth and offsetHeight values

Here is my angular2 code.

Template




Component


    import {Component, OnInit, Input, ViewChild, ElementRef, Renderer} from '@angular/core';
    export class SliderComponent implements OnInit {
      @ViewChild('picker') picker: ElementRef;

      constructor(private renderer: Renderer, private el: ElementRef) {

      }

      ngAfterViewInit() {
        this.renderer.setElementClass(this.picker.nativeElement, 'slider-horizontal', true);

        console.log(this.picker.nativeElement.offsetWidth);
        console.log(this.picker.nativeElement.offsetHeight);
      }
    }

.slider-horizontal {
  width: 210px;
  height: 20px;
}

The problem is the printed values are different for each time loading. I guess this issue is due to the browser have not completed loading the div. Do you know what is the solution for this?

Solved

You have to schedule calls to 'offsetWidth' after rendering cycle, angular executes draw on the end of microtask queue, so you could try setTimeout(..., 0) or run Promise.resolve().then(...) outside of zonejs. Hope it helps.


You can detect size changes by using

MutationObserver

Probably the biggest audience for this new api are the people that write JS frameworks, [...] Another use case would be situations where you are using frameworks that manipulate the DOM and need to react to these modifications efficiently ( and without setTimeout hacks! ).

Here is how you can use it to detect changes in elements :

// select the target node
var target = document.querySelector('#some-id'); // or 

// create an observer instance
var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        console.log(mutation.type);
    });
});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }

// pass in the target node, as well as the observer options
observer.observe(target, config);

// later, you can stop observing
observer.disconnect();

For your case, you could use it inside your ngAfterViewInit and refresh your offsets size. You can be more specific and only detect some mutations, and only then extract your offsets.

more info :

doc: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

compatibility : https://caniuse.com/#feat=mutationobserver

Demo:

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
       console.log(mutation);
       if(mutation.attributeName == 'class') // detect class change
          /*
          or if(mutation.target.clientWidth == myWidth)
          */
          showOffset(mutation.target);
          
          observer.disconnect();
    });
});

var config = { attributes: true}
var demoDiv = document.getElementById('demoDiv');
var logs = document.getElementById('logs');

// wait for document state to be complete
if (document.readyState === "complete") {
    ngAfterViewInit();
  }
  
document.onreadystatechange = function () {
  if (document.readyState === "complete") {
    ngAfterViewInit();
  }
}

// observe changes that effects demoDiv + add class
function ngAfterViewInit(){
 observer.observe(demoDiv, config);
  demoDiv.classList.add('slider-horizontal');
}

// show offsetWidth + height. 
// N.B offset width and height will be bigger than clientWidth because I added a border. If you remove the border you'll see 220px,20px

function showOffset(element){
  offsetMessage = "offsetWidth:" + demoDiv.offsetWidth + " offsetHeight: " + demoDiv.offsetHeight;
 console.log(offsetMessage);
  logs.innerHTML = offsetMessage;
}
.slider-horizontal {
  border: 2px solid red;
  width: 210px;
  height: 20px;
  background: grey;
}
I am a demo div
logs :

Comments

Popular posts from this blog

What's the function of a static constructor in a non static class?

I've noticed that a non-static class can have a static constructor: public class Thing { public Thing() { Console.WriteLine("non-static"); } static Thing() { Console.WriteLine("static"); } } And when you initialize an instance of Thing the static constructor gets called first. Output: static non-static What would be the need for this? Do you use it to initialize static fields on your instance of the non-static type? Are there any things to take into consideration when using a static constructor? Solved Do you use it to initialize static fields on your instance of the non-static type? Pretty much, except that static fields (or static members of any kind) aren't associated with instances; they are associated with the type itself, regardless of whether it is a static class or a non-static class. The documentation lists some properties of static constructors, one of which is: ...

How do list command on one ssh command?

I try connect with ssh2 and run script in one line command. /usr/bin/ssh2 --password ${password} -l root ${address} cd ${dir} ; python script.py But directory isn't changed. Why ? I want write with two command. It does only first command (cd) Solved Hello you should use && instead of ; and put command in " example: /usr/bin/ssh2 --password ${password} -l root ${address} "cd ${dir} && python script.py"

Can I use gulp-imagemin with gulp-watch?

Can I use gulp-imagemin plugin with gulp-watch? So, I need to optimize images as soon as they are put into the folder. Here is a part of my gulpfile.js: var gulp = require('gulp'); var imagemin = require('gulp-imagemin'); var pngquant = require('imagemin-pngquant'); gulp.task('default', function() { gulp.watch('dist/images/**', function(event) { gulp.run('images'); }); }); // Image files gulp.task('images', function () { return gulp.src('src/images/*') .pipe(imagemin({ progressive: true, svgoPlugins: [{removeViewBox: false}], use: [pngquant()] })) .pipe(gulp.dest('dist/images')); }); Solved in your watch task, you're watching image changes in 'dist/images/ ' .. you should change that to **'src/images/*' Also in your image task, you're watching only for images directly in the images folder (non recu...