Javascript Dynamic Function Invocation - javascript

I want to do something kind of Rubyish in Javascript. I'm writing a wrapper around setting DOM element styles. That would go something like (on a per style basis):
ele.style.backgroundColor = someSetting
ele.style.padding = anotherSetting
What I'd like to do (and I'll use Ruby syntax to illustrate) is:
class Element
def initialize(ele)
#ele = ele
end
def setDOMElementStyle(styleSettings = {})
styleSettings.each_pair do |styleAttribute, setting|
#element.style.send(styleAttribute, setting)
end
# Other wrapper stuff for elements here
end
element = Element.new document.createElement("div")
element.setDOMElementStyle :width => '60px', :height => '2px', :top => '0px', :left => '0px'
In Javascript, I can do this with the dreaded eval, but I wondered if there was a neater way to handle it. Here's a hack at it with the evil eval.
var Element, element;
Element = function() {
function Element(element) {
this.element = element;
}
Element.prototype.setDOMElementStyle = function(styleSettings) {
var setting, styleAttribute;
if (styleSettings == null) {
styleSettings = {};
}
for (setting in styleSettings) {
styleAttribute = styleSettings[setting];
eval("#element.style." + styleAttribute + " = " + setting);
}
}
}
element = new Element(document.createElement("div"));
element.setDOMElementStyle({
width: '60px',
height: '2px',
top: '0px',
left: '0px'
});
Thanks!

Use square braces:
element.style[styleAttribute] = setting
In JavaScript, every property can also be referred through square braces. Examples:
window.location.href === window["location"].href === window["location"]["href"]
=== window.location["href"]

Related

Converting Jquery to Vanilla JS - floating elements

//First function -> Makes a heading float when scrolled past it
if (window.matchMedia('(min-width: 767px)').matches) {
$(function(){
var topBlockheight=$('.site-header').height();
// Check the initial Position of the fixed_nav_container
var stickyHeaderTop = $('.float-h2').offset().top;
var stopFloat = $('#stop-float').offset().top;
$(window).scroll(function(){
if( ( $(window).scrollTop() > stickyHeaderTop-topBlockheight && $(window).scrollTop() < stopFloat-topBlockheight )) {
$('.float-h2').css({position: 'fixed', top: '200px'});
}
else {
$('.float-h2').css({position: 'relative', top: '0px'});
}
});
});
}
// Adds Hover effect for boxes
if (window.matchMedia('(min-width: 767px)').matches) {
$(document).ready(function(){
$(".thumb-cta").mouseover(function(){
max_value=4;
random_value= Math.floor((Math.random() * max_value) + 1);
$(this).attr("data-random",random_value);
});
})
}
These are my two only functions in jQuery from my site which i decided to try to rewrite in vanilla JS. The reason for this decision is because I dont want a 90kb file (jquery main file) to be loaded for 2 basic functions (basic but still can't do them, yes I know).
I've tryed to re write them using http://youmightnotneedjquery.com and https://www.workversatile.com/jquery-to-javascript-converter and i ended up with this code, which does not have any errors in the console, but still does not work :((
let el = document.getElementById("masthead");
let topBlockheight = parseFloat(getComputedStyle(el, null).height.replace("px", ""))
var rect = document.getElementById("float-h2").getBoundingClientRect();
var offset = {
top: rect.top + window.scrollY,
left: rect.left + window.scrollX,
};
var brect = document.getElementById("stop-float").getBoundingClientRect();
var boffset = {
top: rect.top + window.scrollY,
left: rect.left + window.scrollX,
};
window.scroll(function(){
if( ( window.scrollTop() > rect-topBlockheight && window.scrollTop() < stopFloat-topBlockheight )) {
document.getElementById("float-h2").css({position: 'fixed', top: '200px'});
}
else {
document.getElementById("float-h2").css({position: 'relative', top: '0px'});
}
});
Any ideas how I can move on, because I'm really stuck
hope this work for you
if (window.matchMedia('(min-width: 767px)').matches) {
//Note: if "site-header" is more than one element remove [0] and create a loop
var topBlockheight=document.getElementsByClassName('site-header')[0].offsetHeight
var stickyHeaderTop = document.getElementsByClassName('float-h2')[0].offsetTop;
var stopFloat = document.getElementById('stop-float').offsetTop;
window.addEventListener("scroll", function(){
if( ( window.scrollY > stickyHeaderTop-topBlockheight && window.scrollY < stopFloat-topBlockheight )) {
document.getElementsByClassName('float-h2')[0].style.position = 'fixed'
document.getElementsByClassName('float-h2')[0].style.top = '200px'
}
else {
document.getElementsByClassName('float-h2')[0].style.position = 'relative'
document.getElementsByClassName('float-h2')[0].style.top = 0
}
});
}
// Adds Hover effect for boxes
if (window.matchMedia('(min-width: 767px)').matches) {
document.onreadystatechange = function(){
if(document.readyState === "interactive") {
document.getElementsByClassName('thumb-cta')[0].addEventListener("mouseover", function(){
max_value=4;
random_value= Math.floor((Math.random() * max_value) + 1);
this.setAttribute("data-random",random_value);
});
}
}
}
Details
jQuery
in jQuery to select elements by className or tagName it's enough to write $('.element') or $('tag') but in Vanillajs to select elements you can use document.getElementsByClassName('elements') or document.getElementsByTagName('elements') which return found elements sharing the same className or tagName in an array if you want to select only one element you can write the element index like document.getElementsByClassName('elements')[0] but if you want to select all elements you will be need to create a loop
var el = document.getElementsByClassName('elements')
for(var i = 0; i < el.length; i++) {
el[i].style.padding = '25px';
el[i].style.background = 'red';
}
and because of id is unque name for the element you don't need to any extra steps you can select it diectly select it like document.getElementById('id')
that was about selecting elements
height() method which uses get the element height - in Vanillajs js to get the element height you can use offsetHeight property or getComputedStyle(element, pseudo|null).cssProp
Example
element.offsetHeight, parseInt(getComputedStyle(element, null).height)
offset() method which uses to return coordinates of the element this method have 2 properties top, left in Vanillajs to get the element offset top you can use offsetTop propery directly like element.offsetTop
jQuery provides a prototype method like css() which provide an easy and readable way to styling elements like in normal object propery: value - in Vanillajs to styling elements you will be need to use style object like element.style.prop = 'value' and you will be need to repeat this line every time you add new css property like
el.style.padding = '25px';
el.style.background = 'red';
//and they will repeated as long as you add new property
if you don't want to include jQuery into your project and need to use this method you can define it as prototype method for HTMLElement, HTMLMediaElement
Example 1: for styling one element
//for html elements
HTMLElement.prototype.css = function(obj) {
for(i in obj) {
this.style[i] = obj[i]
}
}
//for media elements like video, audio
HTMLMediaElement.prototype.css = function(obj) {
for(i in obj) {
this.style[i] = obj[i]
}
}
//Usage
var el = document.getElementsByClassName('elements')[0]
el.css({
'padding': '25px',
'background-color':
})
if you wants to add this style for multiple elements you can define it as prototype method for Array
Example 2: for multiple elements
Array.prototype.css = function(obj) {
for(i = 0; i < this.length; i++) {
if (this[i] instanceof HTMLElement) {
for(r in obj) {
this[i].style[r] = obj[r]
}
}
}
}
//Usage
var el1 = document.getElementsByClassName('elements')[0]
var el2 = document.getElementsByClassName('elements')[1]
[el1, el2].css({
'background-color': 'red',
padding: '25px'
})
jQuery allow you to add events directly when selecting element like $('.element').click(callback) but in Vanillajs you can add events with addEventListener() or onevent proprty like document.getElementById('id').addEventListener('click', callback) , document.getElementById('id').onclick = callback
$(document).ready(callback) this method uses to make your code start working after loading the libraries, other things it's useful to give the lib enough time to loaded to avoid errors - in Vanilla js you can use onreadystatechange event and document.readyState protpety which have 3 values loading, interactive, complete
Example
document.onreadystatechange = function () {
if (document.readyState === 'interactive') {
//your code here
}
}
Your Coverted Code
at this line parseFloat(getComputedStyle(el, null).height.replace("px", "")) you don't need to replace any thing because parseInt(), parseFloat will ignore it
element.css() id don't know how you don't get any errors in the console when this method is undefined you will be need to define it as above to make it work
scroll event is not defined you will be need to use window.onscroll = callback like example above

how to loop and shorten the code

I have similar kind of codes but only a bit different. How to shorten this below code?
Example Below
var sms = document.getElementsByClassName("class-two");
sms.forEach(function(e) {
e.style.width = 200 + 'px';
});
var sms = document.getElementsByClassName("class-one");
sms.forEach(function(e) {
e.style.height = 100 + 'px';
});
The difference between the above is only the class-one and class-two and the two lines e.style.width = 200 + 'px';and e.style.height = 100 + 'px';, Can I use loop here and how?
Adhering to the DRY (Don't Repeat Yourself) principle, you could write a function to encapsulate your redundant code:
function setWidth(cls, attr, pixels) {
Array.from(document.getElementsByClassName(cls)).forEach(function(e) {
e.style[attr] = pixels + 'px';
});
}
setWidth("class-two", "width", 200);
setWidth("class-one", "height", 100);
Using Array#forEach and creating a function which can be called with the class, style attribute and value ..
function setThings(cls, attr, value) {
[].forEach.call(document.getElementsByClassName(cls), function(el) {
el.style[attr] = value;
});
}
setThings("class-two", 'width', '200px');
setThings("class-one", 'height', '100px');
However, even after fixing the questions misuse of forEach
[].forEach.call(document.getElementsByClassName("class-two"), function(e) {
e.style.width = '200px';
});
[].forEach.call(document.getElementsByClassName("class-one"), function(e) {
e.style.height = '100px';
});
is actually shorter code, unless the function (setThings) is named with a single character, then the first answer is shorter
It's considered bad practice to set CSS styles directly on elements as you are doing, and it's not necessary. You can simplify your code greatly by intelligent use of CSS, reducing the amount of JS to essentially one line to toggle a class on a higher-level element which drives the width or height of the child elements, thereby eliminating any need for loops or functions. You'll have less code to write, debug, and maintain. Essentially, instead of finding all the elements with a particular class yourself in JS, you let the CSS engine do that, which is what it does for a living!
const topElement = document.getElementById('top');
const buttonElement = document.getElementById('button');
function toggle() { topElement.classList.toggle('narrow'); }
buttonElement.addEventListener('click', toggle);
.class-one, .class-two { width: 300px; height: 16px; }
.class-one { background: red; }
.class-two { background: blue; }
.narrow .class-one { width: 200px; }
.narrow .class-two { height: 100px; }
<div id="top">
<div class="class-one"></div>
<div class="class-two"></div>
</div>
<button id="button">Toggle</button>
#qxz answer seems best.
But if you want to avoid function call, refer this:
[].forEach.call(document.querySelectorAll('.class-two,.class-one'), function(e) {
if (e.className.includes("class-two")) {
e.style.width = "200px";
};
if (e.className.includes("class-one")) {
e.style.height = "100px";
};
});
A fiddle for you

Potentially suffering from over optimization

I have this design for the front page of a personal website I'm making:
You click on the respective icon and it expands to reveal info.I went through two other designs that didn't work out, but incorporated similar animations. After modifying the JS after each iteration I realized that I was:
Encountering bits of redundant code
Starting to consider the potentiality of adding more tabs/sections in the future (that I might need to make the code scale)
This lead me to start 'generacizing' my code. So making functions like 'handleHorizontalTabs' or 'handleVerticalTabs' rather than 'handleGamesTab' or 'handlePhotographyTab' This would avoid me writing a whole new function for the photography tab, which differs from the games tab by only one css property. So I was thinking, well then I'm going to need to pass in an object rather than an exact ID. Then I created some object literals that stored all of their respective properties. The problem with creating neutral animation functions like this (in my case at least) is that I HAVE to define every property that could be used in the function even if it's not used. Consider this snippet before you scroll to the full code:
if (active){
// Only animate horizontally
$(elemToAnimate.ID).animate({
width: elemToAnimate.ExpandedWidth,
left: elemToAnimate.ExpandedLeft,
right: elemToAnimate.ExpandedRight
}, animateDuration)
}
I might not need to change the say,'left' property, when animating. But because this is a general function it doesn't know that. So, in my object literal I still have to define it (it would just be the original value). I did notice (and I left the game section unchanged so you could see this) that if I simply leave it out of the literal, it is marked as undefined and has no effect on the animation. I could do this, but I don't think that's good practice. Plus anyone reading my code would be asking where that property is.
My question is two fold:
What should I consider programmatically when taking the scalability of an app into account?
How can this code be cleaned up/refined?
The code:
https://jsfiddle.net/rc6wnsst/
(PS Not browser optimized; use Mozilla if you can)
$(document).ready(function() {
// Definitions
//Define object literals
var aboutmeSection = {id: '#aboutme-section', get ID() {return this.id;},
selector: '#person-icon', get Selector() {return this.selector;},
origWidth: $('#aboutme-section').css('width'), get OrigWidth() {return this.origWidth;},
origLeft: $('#aboutme-section').css('left'), get OrigLeft() {return this.origLeft;},
origRight: 'auto', get OrigRight() {return this.origRight;},
origHeight: $('#aboutme-section').css('height'), get OrigHeight() {return this.origHeight;},
origTop: $('#aboutme-section').css('top'), get OrigTop() {return this.origTop;},
origBottom: $('#aboutme-section').css('bottom'), get OrigBottom() {return this.origBottom;},
expandedWidth: '65%', get ExpandedWidth() {return this.expandedWidth;},
expandedLeft: $('#aboutme-section').css('left'), get ExpandedLeft() {return this.expandedLef;},
expandedRight: $('#aboutme-section').css('right'), get ExpandedRight() {return this.expandedRight;},
expandedHeight: '450px', get ExpandedHeight() {return this.expandedHeight;},
expandedTop: '65%', get ExpandedTop() {return this.expandedTop;},
expandedBottom: $('#aboutme-section').css('bottom'), get ExpandedBottom() {return this.expandedBottom;}};
var photographySection = {id: '#photography-tab', get ID() {return this.id;},
selector: '#camera-icon', get Selector() {return this.selector;},
origWidth: $('#photography-tab').css('width'), get OrigWidth() {return this.origWidth;},
origLeft: 'auto', get OrigLeft() {return this.origLeft;},
origRight: $('#photography-tab').css('right'), get OrigRight() {return this.origRight;},
expandedWidth: '40%', get ExpandedWidth() {return this.expandedWidth;},
expandedLeft: 'auto', get ExpandedLeft() {return this.expandedLeft;},
expandedRight: $('#photography-tab').css('right'), get ExpandedRight() {return this.expandedRight;}};
var gamesSection = {id: '#games-tab', get ID() {return this.id;},
selector: '#gamepad-icon', get Selector() {return this.selector;},
origWidth: $('#games-tab').css('width'), get OrigWidth() {return this.origWidth;},
origLeft: $('#games-tab').css('left'), get OrigLeft() {return this.origLeft;},
expandedWidth: '40%', get ExpandedWidth() {return this.expandedWidth;}};
Handlers
// Handles aboutme section functionality
function handleAboutMeSection(elemToAnimate, selectedElem, active, animateDuration=500, fadeInDuration=500, fadeOutDuration=250){
// First click
if (active){
// Animate vertically first
$(elemToAnimate.ID).animate({height: elemToAnimate.ExpandedHeight,
top: elemToAnimate.ExpandedTop,
bottom: elemToAnimate.OrigBottom}, animateDuration);
// Animate horizontally second
$(elemToAnimate.ID).animate({width: elemToAnimate.ExpandedWidth,
left: elemToAnimate.ExpandedLeft,
right: elemToAnimate.ExpandedRight}, animateDuration)
// Fade in content and remove active class
$(elemToAnimate.ID).find(".content").fadeIn(fadeInDuration);
$(selectedElem).removeClass('active');
// Second click
} else {
// Fade out content
$(elemToAnimate.ID).find(".content").fadeOut(fadeOutDuration, function(){
// Animate horizontally first
$(elemToAnimate.ID).animate({width: elemToAnimate.OrigWidth,
left: elemToAnimate.OrigLeft,
right: elemToAnimate.OrigRight}, animateDuration);
// Animate vertically second
$(elemToAnimate.ID).animate({height: elemToAnimate.OrigHeight,
top: elemToAnimate.OrigTop,
bottom: elemToAnimate.OrigBottom}, animateDuration)
});
// Add active class back in
$(selectedElem).addClass('active');
}
}
//Handles photography tab functionality
function handleTabs(elemToAnimate, selectedElem, active, animateDuration=500, fadeInDuration=500, fadeOutDuration=250){
// First click
if (active){
// Only animate horizontally
$(elemToAnimate.ID).animate({width: elemToAnimate.ExpandedWidth,
left: elemToAnimate.ExpandedLeft,
right: elemToAnimate.ExpandedRight}, animateDuration)
// Fade in content and remove active class
$(elemToAnimate.ID).find(".content").fadeIn(fadeInDuration);
$(selectedElem).removeClass('active');
// Second click
} else {
// Fade out content and only animate horizontally
$(elemToAnimate.ID).find(".content").fadeOut(fadeOutDuration, function(){
$(elemToAnimate.ID).animate({width: elemToAnimate.OrigWidth,
left: elemToAnimate.OrigLeft,
right: elemToAnimate.OrigRight}, animateDuration);
});
// Add active class back in
$(selectedElem).addClass('active');
}
}
Main
//Hide content initially
$(".content").hide();
//Handle click events
$(".image").click(function() {
//On first click
if ($(this).hasClass("active")) {
switch($(this).attr('id')) {
case 'person-icon':
handleAboutMeSection(aboutmeSection, aboutmeSection.Selector, true);
break;
case 'gamepad-icon':
handleTabs(gamesSection, gamesSection.Selector, true);
break;
case 'camera-icon':
handleTabs(photographySection, photographySection.Selector, true);
break;
default:
break;
}
// On second click
} else {
switch($(this).attr('id')) {
case 'person-icon':
handleAboutMeSection(aboutmeSection, aboutmeSection.Selector, false);
break;
case 'gamepad-icon':
handleTabs(gamesSection, gamesSection.Selector, false);
break;
case 'camera-icon':
handleTabs(photographySection, photographySection.Selector, false);
break;
default:
break;
}
}
});
});
You're right. It has a TL:DR feel to it.
However I think I know what you are going through so let me address your questions and just glimpse over the code:
1) What should I consider programmatically when taking the scalability of an app into account? How can this code be cleaned up/refined?
This depends on what you plan to do with it. Do you need to implement more blocks, maybe use tabs and blocks together to have several different options ? More important than that, do you wish to come back a few years later and don't slap yourself in the forehead, then yes, you probably could refactor this a bit.
Before I start, take this with a grain of salt. Every programmer is different, so my refactor examples may not tingle with others. If the code works, it is #right#. Only the code with errors is #wrong#. Again, another opinion of mine.
So, what I would do is create a settings literal object to deal with the section part, that contained what you needed. Lets take about me for example. Here's how I would do just the js code:
// Definitions ----------------------------------------
var section = {
elem: null,
selector: null,
content: null,
opened: false,
origDim: { },
currDim: { },
expdDim: { },
setup: function(settings) { // gets the settings and sets up the initial position
var self = this;
if ( !(
self.is_set(settings) ||
self.is_set(settings.elem) ||
self.is_set(settings.selector) ||
self.is_set(settings.content)
)
)
{
console.log('Your settings must send out an element, a content and a selector');
} else {
self.elem = settings.elem;
self.selector = settings.selector;
self.content = settings.content;
self.origDim = self.getPosition();
}
return self; // this allows chaining
},
// Sets up the range of motion the section will have
setRange: function(expdDim) {
var self = this;
if ( !(self.is_set(expdDim)) ) {
console.log('You have to provide a set of new positions.')
} else {
self.expdDim = {
width: (self.is_set(expdDim.width)?expdDim.width:self.currDim.width),
height: (self.is_set(expdDim.height)?expdDim.height:self.currDim.height),
top: (self.is_set(expdDim.top)?expdDim.top:self.currDim.top),
right: (self.is_set(expdDim.right)?expdDim.right:self.currDim.right),
bottom: (self.is_set(expdDim.bottom)?expdDim.bottom:self.currDim.bottom),
left: (self.is_set(expdDim.left)?expdDim.left:self.currDim.left)
};
}
return self; // this allows chaining
},
// Toggles from opened to close by listening to a property opened
toggle: function(animTime, fadeInTime, fadeOutTime) {
var self = this;
if (self.opened) self.close(animTime, fadeOutTime);
else self.open(self.expdDim, animTime, fadeInTime);
return self; // this allows chaining
},
// Expands the section
open: function(newDim, animTime, fadeInTime) {
var self = this;
if ( !(self.is_set(newDim)) ) console.log('You must send new dimensions!');
else {
var elem = $(self.elem);
elem
.animate(self.optionsVert(newDim), animTime)
.animate(self.optionsHorz(newDim), animTime)
.promise().done( function() {
$(this).find(self.content).fadeIn(fadeInTime)
self.currDim = self.getPosition();
self.opened = true;
});
}
return self; // this allows chaining
},
// Closes the section
close: function(animTime, fadeOutTime) {
var self = this;
var elem = $(self.elem);
// first fade
elem.find(self.content)
.fadeOut(fadeOutTime)
.promise()
.done(function(){
elem
.animate(self.optionsHorz(self.origDim), animTime)
.animate(self.optionsVert(self.origDim), animTime)
.promise()
.done( function() {
self.currDim = self.getPosition();
self.opened = false;
});
});
return self; // this allows chaining
},
// HELPER FUNCTIONS - these do not allow chaining - used as private functions
// Sets up original dimensions based on the element
getPosition: function() {
var self = this;
var offset = $(self.elem).offset();
var posDim = {
width: $(self.elem).width()+'px',
height: $(self.elem).height()+'px',
top: offset.top+'px',
right: parseInt(offset.left)+parseInt($(self.elem).width())+'px',
bottom: parseInt(offset.top)+parseInt($(self.elem).height())+'px',
left: offset.left+'px'
};
return posDim;
},
// validates if a given variable is set
is_set: function(vary) {
return (typeof vary != 'undefined');
},
// returns a subset of dimension variables belonging to the X plane
optionsHorz: function(newDim) {
return {
width: newDim.width,
left: newDim.left,
right: newDim.right
};
},
// returns a subset of dimension variables belonging to the Y plane
optionsVert: function(newDim) {
return {
height: newDim.height,
top: newDim.top,
bottom: newDim.bottom
};
}
};
// Definitions ----------------------------------------
$(document).ready(function() {
// Setting up section about me
var aboutme = section;
aboutme.setup({
elem: '#aboutme-section',
selector: '#person-icon',
content: '.content'
}).setRange({
width: '65%',
height: '450px',
top: '65%'
});
//Hide content initially
$(".content").hide();
//Handle click events
$(".image").click(function() {
switch($(this).attr('id')) {
case 'person-icon':
aboutme.toggle(500,500,250);
break;
default:
break;
}
});
});
This is how you can templatize your sections. You can augment this block to augment it's functionality but, if you take a look, the settings get pretty thin and simple.
Hope this helps.

-webkit-transform: incremental reposition with += operator not working

I am trying to incrementally reposition an element by setting the -webkit-transform property to +=200px
But it doesn't work. I'm missing something, but don't know what.
http://jsfiddle.net/yVSDC/
Clicking the div is supposed to move it further down by 200px everytime.
CSS doesn't work like that, and jQuery doesn't pull that data out so you can do it like that.
You'd need to read the value, add 200 and then reset it.
var getTranslatedY = function (element) {
var transform = element.css("transform") || element.css("-webkit-transform") || element.css("-moz-transform");
if (transform == "none") {
return 0;
}
return parseInt((transform.match(/^matrix\(.*?(-?[\d.]+)\)$/) || [])[1]) || 0;
};
$('#m').on(
'click',
function () {
var element = $(this);
element
.css('-webkit-transform',
"translateY(" + (getTranslatedY(element) + 200) + "px)");
});
jsFiddle.
var step = 200;
$('body').on('click', "#m", function(){
$(this).css('-webkit-transform','translateY('+ step +'px)');
step = step+200;
});
And instead -webkit-transform:translateY(100px); in CSS you can set margin-top: 100px;
http://jsfiddle.net/yVSDC/28/
You have to get the Current webkit-transform value and increment it. Alternative Solution is ustin the top CSS Property
You can try this (it's free): http://ricostacruz.com/jquery.transit/
Sample Code:
$('.box').transition({ x: '200px' });
$('.box').transition({ y: '200px' });
$('.box').transition({ x: '200px', y: '200px' });

How can I set multiple CSS styles in JavaScript?

I have the following JavaScript variables:
var fontsize = "12px"
var left= "200px"
var top= "100px"
I know that I can set them to my element iteratively like this:
document.getElementById("myElement").style.top=top
document.getElementById("myElement").style.left=left
Is it possible to set them all together at once, something like this?
document.getElementById("myElement").style = allMyStyle
If you have the CSS values as string and there is no other CSS already set for the element (or you don't care about overwriting), make use of the cssText property:
document.getElementById("myElement").style.cssText = "display: block; position: absolute";
You can also use template literals for an easier, more readable multiline CSS-like syntax:
document.getElementById("myElement").style.cssText = `
display: block;
position: absolute;
`;
This is good in a sense as it avoids repainting the element every time you change a property (you change them all "at once" somehow).
On the other side, you would have to build the string first.
Using Object.assign:
Object.assign(yourelement.style,{fontsize:"12px",left:"200px",top:"100px"});
This also gives you ability to merge styles, instead of rewriting the CSS style.
You can also make a shortcut function:
const setStylesOnElement = function(styles, element){
Object.assign(element.style, styles);
}
#Mircea: It is very much easy to set the multiple styles for an element in a single statement.
It doesn't effect the existing properties and avoids the complexity of going for loops or plugins.
document.getElementById("demo").setAttribute(
"style", "font-size: 100px; font-style: italic; color:#ff0000;");
BE CAREFUL: If, later on, you use this method to add or alter style properties, the previous properties set using 'setAttribute' will be erased.
Make a function to take care of it, and pass it parameters with the styles you want changed..
function setStyle( objId, propertyObject )
{
var elem = document.getElementById(objId);
for (var property in propertyObject)
elem.style[property] = propertyObject[property];
}
and call it like this
setStyle('myElement', {'fontsize':'12px', 'left':'200px'});
for the values of the properties inside the propertyObject you can use variables..
I just stumbled in here and I don't see why there is so much code required to achieve this.
Add your CSS code using String Interpolation.
let styles = `
font-size:15em;
color:red;
transform:rotate(20deg)`
document.querySelector('*').style = styles
a
A JavaScript library allows you to do these things very easily
jQuery
$('#myElement').css({
font-size: '12px',
left: '200px',
top: '100px'
});
Object and a for-in-loop
Or, a much more elegant method is a basic object & for-loop
var el = document.getElementById('#myElement'),
css = {
font-size: '12px',
left: '200px',
top: '100px'
};
for(i in css){
el.style[i] = css[i];
}
set multiple css style properties in Javascript
document.getElementById("yourElement").style.cssText = cssString;
or
document.getElementById("yourElement").setAttribute("style",cssString);
Example:
document
.getElementById("demo")
.style
.cssText = "margin-left:100px;background-color:red";
document
.getElementById("demo")
.setAttribute("style","margin-left:100px; background-color:red");
Strongly typed in typescript:
The object.assign method is great, but with typescript you can get autocomplete like this:
const newStyle: Partial<CSSStyleDeclaration> =
{
placeSelf: 'centered centered',
margin: '2em',
border: '2px solid hotpink'
};
Object.assign(element.style, newStyle);
Note the property names are camelCase not with dashes.
This will even tell you when they're deprecated.
You can have individual classes in your css files and then assign the classname to your element
or you can loop through properties of styles as -
var css = { "font-size": "12px", "left": "200px", "top": "100px" };
for(var prop in css) {
document.getElementById("myId").style[prop] = css[prop];
}
Simplest way for me was just using a string/template litteral:
elementName.style.cssText = `
width:80%;
margin: 2vh auto;
background-color: rgba(5,5,5,0.9);
box-shadow: 15px 15px 200px black; `;
Great option cause you can use multiple line strings making life easy.
Check out string/template litterals here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
Using plain Javascript, you can't set all the styles at once; you need to use single lines for each of them.
However, you don't have to repeat the document.getElementById(...).style. code over and over; create an object variable to reference it, and you'll make your code much more readable:
var obj=document.getElementById("myElement").style;
obj.top=top;
obj.left=left;
...etc. Much easier to read than your example (and frankly, just as easy to read as the jQuery alternative).
(if Javascript had been designed properly, you could also have used the with keyword, but that's best left alone, as it can cause some nasty namespace issues)
Since strings support adding, you can easily add your new style without overriding the current:
document.getElementById("myElement").style.cssText += `
font-size: 12px;
left: 200px;
top: 100px;
`;
Don't think it is possible as such.
But you could create an object out of the style definitions and just loop through them.
var allMyStyle = {
fontsize: '12px',
left: '200px',
top: '100px'
};
for (i in allMyStyle)
document.getElementById("myElement").style[i] = allMyStyle[i];
To develop further, make a function for it:
function setStyles(element, styles) {
for (i in styles)
element.style[i] = styles[i];
}
setStyles(document.getElementById("myElement"), allMyStyle);
Your best bet may be to create a function that sets styles on your own:
var setStyle = function(p_elem, p_styles)
{
var s;
for (s in p_styles)
{
p_elem.style[s] = p_styles[s];
}
}
setStyle(myDiv, {'color': '#F00', 'backgroundColor': '#000'});
setStyle(myDiv, {'color': mycolorvar, 'backgroundColor': mybgvar});
Note that you will still have to use the javascript-compatible property names (hence backgroundColor)
See for .. in
Example:
var myStyle = {};
myStyle.fontsize = "12px";
myStyle.left= "200px";
myStyle.top= "100px";
var elem = document.getElementById("myElement");
var elemStyle = elem.style;
for(var prop in myStyle) {
elemStyle[prop] = myStyle[prop];
}
This is old thread, so I figured for anyone looking for a modern answer, I would suggest using Object.keys();
var myDiv = document.getElementById("myDiv");
var css = {
"font-size": "14px",
"color": "#447",
"font-family": "Arial",
"text-decoration": "underline"
};
function applyInlineStyles(obj) {
var result = "";
Object.keys(obj).forEach(function (prop) {
result += prop + ": " + obj[prop] + "; ";
});
return result;
}
myDiv.style = applyInlineStyles(css);
Use CSSStyleDeclaration.setProperty() method inside the Object.entries of styles object.
We can also set the priority ("important") for CSS property with this.
We will use "hypen-case" CSS property names.
const styles = {
"font-size": "18px",
"font-weight": "bold",
"background-color": "lightgrey",
color: "red",
"padding": "10px !important",
margin: "20px",
width: "100px !important",
border: "1px solid blue"
};
const elem = document.getElementById("my_div");
Object.entries(styles).forEach(([prop, val]) => {
const [value, pri = ""] = val.split("!");
elem.style.setProperty(prop, value, pri);
});
<div id="my_div"> Hello </div>
There are scenarios where using CSS alongside javascript might make more sense with such a problem. Take a look at the following code:
document.getElementById("myElement").classList.add("newStyle");
document.getElementById("myElement").classList.remove("newStyle");
This simply switches between CSS classes and solves so many problems related with overriding styles. It even makes your code more tidy.
I think is this a very simple way with regards to all solutions above:
const elm = document.getElementById("myElement")
const allMyStyle = [
{ prop: "position", value: "fixed" },
{ prop: "boxSizing", value: "border-box" },
{ prop: "opacity", value: 0.9 },
{ prop: "zIndex", value: 1000 },
];
allMyStyle.forEach(({ prop, value }) => {
elm.style[prop] = value;
});
This is an old question but I thought it might be worthwhile to use a function for anyone not wanting to overwrite previously declared styles. The function below still uses Object.assign to properly fix in the styles. Here is what I did
function cssFormat(cssText){
let cssObj = cssText.split(";");
let css = {};
cssObj.forEach( style => {
prop = style.split(":");
if(prop.length == 2){
css[prop[0]].trim() = prop[1].trim();
}
})
return css;
}
Now you can do something like
let mycssText = "background-color:red; color:white;";
let element = document.querySelector("body");
Object.assign(element.style, cssFormat(mycssText));
You can make this easier by supplying both the element selector and text into the function and then you won't have to use Object.assign every time. For example
function cssFormat(selector, cssText){
let cssObj = cssText.split(";");
let css = {};
cssObj.forEach( style => {
prop = style.split(":");
if(prop.length == 2){
css[prop[0]].trim() = prop[1].trim();
}
})
element = document.querySelector(selector);
Object.assign(element.style, css); // css, from previous code
}
Now you can do:
cssFormat('body', 'background-color: red; color:white;') ;
//or same as above (another sample)
cssFormat('body', 'backgroundColor: red; color:white;') ;
Note: Make sure your document or target element (for example, body) is already loaded before selecting it.
You can write a function that will set declarations individually in order not to overwrite any existing declarations that you don't supply. Let's say you have this object parameter list of declarations:
const myStyles = {
'background-color': 'magenta',
'border': '10px dotted cyan',
'border-radius': '5px',
'box-sizing': 'border-box',
'color': 'yellow',
'display': 'inline-block',
'font-family': 'monospace',
'font-size': '20px',
'margin': '1em',
'padding': '1em'
};
You might write a function that looks like this:
function applyStyles (el, styles) {
for (const prop in styles) {
el.style.setProperty(prop, styles[prop]);
}
};
which takes an element and an object property list of style declarations to apply to that object. Here's a usage example:
const p = document.createElement('p');
p.textContent = 'This is a paragraph.';
document.body.appendChild(p);
applyStyles(p, myStyles);
applyStyles(document.body, {'background-color': 'grey'});
// styles to apply
const myStyles = {
'background-color': 'magenta',
'border': '10px dotted cyan',
'border-radius': '5px',
'box-sizing': 'border-box',
'color': 'yellow',
'display': 'inline-block',
'font-family': 'monospace',
'font-size': '20px',
'margin': '1em',
'padding': '1em'
};
function applyStyles (el, styles) {
for (const prop in styles) {
el.style.setProperty(prop, styles[prop]);
}
};
// create example paragraph and append it to the page body
const p = document.createElement('p');
p.textContent = 'This is a paragraph.';
document.body.appendChild(p);
// when the paragraph is clicked, call the function, providing the
// paragraph and myStyles object as arguments
p.onclick = (ev) => {
applyStyles(p, myStyles);
}
// this time, target the page body and supply an object literal
applyStyles(document.body, {'background-color': 'grey'});
With ES6+ you can use also backticks and even copy the css directly from somewhere:
const $div = document.createElement('div')
$div.innerText = 'HELLO'
$div.style.cssText = `
background-color: rgb(26, 188, 156);
width: 100px;
height: 30px;
border-radius: 7px;
text-align: center;
padding-top: 10px;
font-weight: bold;
`
document.body.append($div)
Please consider the use of CSS for adding style class and then add this class by JavaScript
classList & simply add() function.
style.css
.nice-style {
fontsize : 12px;
left: 200px;
top: 100px;
}
script JavaScript
const addStyle = document.getElementById("myElement");
addStyle.classList.add('nice-style');
<button onclick="hello()">Click!</button>
<p id="demo" style="background: black; color: aliceblue;">
hello!!!
</p>
<script>
function hello()
{
(document.getElementById("demo").style.cssText =
"font-size: 40px; background: #f00; text-align: center;")
}
</script>
We can add styles function to Node prototype:
Node.prototype.styles=function(obj){ for (var k in obj) this.style[k] = obj[k];}
Then, simply call styles method on any Node:
elem.styles({display:'block', zIndex:10, transitionDuration:'1s', left:0});
It will preserve any other existing styles and overwrite values present in the object parameter.
Is the below innerHtml valid
var styleElement = win.document.createElement("STYLE");
styleElement.innerHTML = "#notEditableVatDisplay {display:inline-flex} #editableVatInput,.print-section,i.fa.fa-sort.click-sortable{display : none !important}";
Different ways to achieve this:
1. document.getElementById("ID").style.cssText = "display:block; position:relative; font-size:50px";
2. var styles = {"display":"block"; "position":"relative"; "font-size":"50px"};
var obj = document.getElementById("ID");
Object.assign(obj.style, styles);
3. var obj = document.getElementById("ID");
obj.setAttribute("style", "display:block; position:relative; font-size:50px");
Hope this helps ~ RDaksh
var styles = {
"background-color": "lightgray",
"width": "500px",
"height": "300px"
};
/
var obj = document.getElementById("container");
Object.assign(obj.style, styles);

Categories

Resources