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
5 Answers
Reset to default 7I'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.