最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Uncaught TypeError: Cannot set property offsetWidth of #<HTMLElement> which has only a getter - Stack

programmeradmin3浏览0评论

I'm developing a web app with AngularJS. I had an error which appeared from nowhere, it was working fine and I really don't know why it doesn't work anymore.

So it's in a directive, I try to set property offsetWidth of an element in the directive html template. Since I really don't know where it could come from, I'll give you full code of my directive and template. The directive creates an app button and handles its visual effect on click. It's the line $element[0].offsetWidth = $element[0].offsetWidth; which triggers the error. (It's a trick to restart animation)

I repeat again, this code was working fine and I'm almost sure I didn't make any changes. I'm using Chrome to debug, maybe it comes from it ?

Error: Uncaught TypeError: Cannot set property offsetWidth of #<HTMLElement> which has only a getter

Directive:

'use strict';

XVMApp.directive('appButton', ['$location', function($location){
    return {
        restrict: 'E',
        replace: true,
        scope: {
            img: '@',
            fillPercent: '@?',
            target: '@?'
        },
        link: function ($scope, $element) {

            // Image percentage fill button
            if($scope.fillPercent === undefined) $scope.fillPercent = '100';

            // Click event
            $element.on('click', function() {

                // Url target
                if($scope.target !== undefined){
                    $scope.$apply(function() {
                        $location.path($scope.target);
                    });
                }

                // Click effect
                $element[0].preventDefault;
                $element[0].classList.remove('app-button-click-effect');
                $element[0].offsetWidth = $element[0].offsetWidth;
                $element[0].classList.add('app-button-click-effect');

            });

        },
        templateUrl: 'src/directive/appButton/app-button.html'
    };
}]);

Template:

<div class="app-button"
     style="background-size: {{fillPercent}}%; ">
        <div style="
            background-image: url('src/assets/img/{{img}}');
            background-repeat: no-repeat;
            background-position: center;
            background-size: {{fillPercent}}%;
            height: 100%;
            width: 100%; ">
        </div>
</div>

I'm developing a web app with AngularJS. I had an error which appeared from nowhere, it was working fine and I really don't know why it doesn't work anymore.

So it's in a directive, I try to set property offsetWidth of an element in the directive html template. Since I really don't know where it could come from, I'll give you full code of my directive and template. The directive creates an app button and handles its visual effect on click. It's the line $element[0].offsetWidth = $element[0].offsetWidth; which triggers the error. (It's a trick to restart animation)

I repeat again, this code was working fine and I'm almost sure I didn't make any changes. I'm using Chrome to debug, maybe it comes from it ?

Error: Uncaught TypeError: Cannot set property offsetWidth of #<HTMLElement> which has only a getter

Directive:

'use strict';

XVMApp.directive('appButton', ['$location', function($location){
    return {
        restrict: 'E',
        replace: true,
        scope: {
            img: '@',
            fillPercent: '@?',
            target: '@?'
        },
        link: function ($scope, $element) {

            // Image percentage fill button
            if($scope.fillPercent === undefined) $scope.fillPercent = '100';

            // Click event
            $element.on('click', function() {

                // Url target
                if($scope.target !== undefined){
                    $scope.$apply(function() {
                        $location.path($scope.target);
                    });
                }

                // Click effect
                $element[0].preventDefault;
                $element[0].classList.remove('app-button-click-effect');
                $element[0].offsetWidth = $element[0].offsetWidth;
                $element[0].classList.add('app-button-click-effect');

            });

        },
        templateUrl: 'src/directive/appButton/app-button.html'
    };
}]);

Template:

<div class="app-button"
     style="background-size: {{fillPercent}}%; ">
        <div style="
            background-image: url('src/assets/img/{{img}}');
            background-repeat: no-repeat;
            background-position: center;
            background-size: {{fillPercent}}%;
            height: 100%;
            width: 100%; ">
        </div>
</div>
Share Improve this question edited Sep 14, 2016 at 8:09 danwellman 9,2538 gold badges63 silver badges91 bronze badges asked May 26, 2015 at 8:15 sylvain1264sylvain1264 8552 gold badges8 silver badges23 bronze badges 1
  • If I only get offsetWidth value the restart animation trick works anyway ($element[0].offsetWidth;), so my problem is fixed. But I'm still wondering why I can't set a value to offsetWidth property ? – sylvain1264 Commented May 26, 2015 at 10:37
Add a comment  | 

5 Answers 5

Reset to default 7

I'm guessing you've recently updated to Chrome 43. I just encountered the same issue. Looks like the latest version treats dom nodes more like standard js classes, and any properties that are read only will now throw a js error. Setting the offsetWidth would never have been working anyway as it's a read only property, but previously Chrome would have just silently ignored it, whereas now if you're using strict mode it's throwing this error. See here for details: http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype

According to this answer you just need to access the property to trigger a reflow.
So this should be enough to reset your animation :

$element[0].classList.remove('app-button-click-effect');
$element[0].offsetWidth;
$element[0].classList.add('app-button-click-effect');

I've done quick tests on chromium and firefox and both works.

If in your use case throwing a temporary band-aid would be acceptable, you could just suppress the error message using the technique described next:

In any .js file in the library, search for "use strict", and comment the line out that has this this line. For example, in the file jquery-1.9.1.js on line 39, there is a line which is:

"use strict";

I made it

//"use strict";

I did this everywhere I found "use strict";

Edit:

Simply hiding the error will not actually fix the problem, and may hide additional problems as well. As mentioned in a different answer, as of Chrome 43, an error will be raised if you try to write to read-only DOM properties regardless of whether or not you are explicitly using "use strict" in your code. In summary, don't write to read-only DOM properties...

To fix the problem and to avoid jshint error (expected an assignment or a function call) You should do:

$element[0].classList.remove('app-button-click-effect');
(function(){  
  return $element[0].offsetWidth;
})();
$element[0].classList.add('app-button-click-effect');

BTW How come answers like below //"use strict"; could penetrate into? This is a good example of what this site is about. Fake questions. Fake answers. Fake traffic. Very sad thing.

If you just want to set the offsetWidth just do:

$element[0].style.offsetWidth = $element[0].offsetWidth

Instead of:

$element[0].offsetWidth = $element[0].offsetWidth;

Which is only a getter property.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论