I'm trying to get my website to scale its width when the window size is changed.
JQuery:
$(window).resize(function() {
var w = $("body").width();
if(w-810 < 0) {
$("body").css("Left","0px");
}
else {
var width = w.toString() + "px";
$("body").css("Left",width);
}
});
CSS:
body {
background-color: #eeeeee;
position: relative;
left: 20%;
}
HTML:
<script src="scripts\jquery.min.js" type="text/javascript"></script>
<script src="scripts\myJavascript.js" type="text/javascript"></script>
....
<body class="body">
One thing I have noticed, if I select the body by class (change in jquery to "#body"), it always defaults to 0px for the width.
Any ideas?
If you want to get the body element by a class, you must use the '.body' selector. If you want to get elements with their id, use '#body'
Try to put the CSS in lowercase, better passing in an object as parameter. Moreover, try also to "cache" the body element in order to prevent several, unnecessary querys to the DOM tree:
var body = $('.body');
$(window).resize(function() {
var w = body.width();
if (w-810 < 0) {
w = "0";
}
body.css({ "left" : w + "px" });
});
The body class is '.body', not '#body'
Related
This question already has answers here:
How do I retrieve an HTML element's actual width and height?
(16 answers)
How to get actual CSS property value of an HTML element node? [duplicate]
(5 answers)
Closed 4 years ago.
I am a beginner coder. It is probably very simple, but I tried to find the answer and have not succeeded. My question is why do width and height properties of div object return undefined while they are apparently 100px both?
In this topic is explained how to get .offsetWidth property. But as I understand it is not 100% the same as .width.
window.onload = function() {
var test = document.getElementById("test");
test.addEventListener("click", select);
function select(e) {
var elementID = e.target.id;
var element = document.getElementById(elementID);
var width = element.width;
console.log(element);
console.log(width);
}
}
div#test {
position: absolute;
height: 100px;
width: 100px;
background-color: black;
}
<div id="test"></div>
My answer
Thank you all guys for your answers. They pushed me to find my own simple solution which I hope will be helpful for such beginners as me. The answer is: div DOM object does not have .width and .height property even if you assign them in CSS and they work well. For this purpose it has .style.width and .style.height respectively. But even if you assign them through CSS they will not appear in element.style until you do it purposefully using Java Script. So to get width or height of the div element through JS first of all remove these properties from CSS. You will not need them anymore. Then assign width through element.style.width command and then you can easily get it whenever you want using element.style.width.
CSS
div {
position: absolute;
background-color: black;
}
JavaScript
window.onload = function() {
var test = document.getElementById("test");
test.addEventListener("click", select);
test.style.width = "100px";
test.style.height = "100px";
function select(e) {
var elementID = e.target.id;
var element = document.getElementById(elementID);
var width = element.style.width;
console.log(element);
console.log(width);
}
}
Use offsetWidth and offsetHeight
var test = document.getElementById("test");
test.addEventListener("click", select);
function select(e) {
var elementID = e.target.id;
var element = document.getElementById(elementID);
var offsetWidth = element.offsetWidth;
var positionInfo = element.getBoundingClientRect();
var height = positionInfo.height;
var width = positionInfo.width;
console.log('element', element);
console.log('offsetWidth', offsetWidth);
console.log('width', width);
console.log('height', height);
}
div#test {
position: absolute;
height: 100px;
width: 100px;
background-color: black;
}
<!doctype html>
<html lang="en">
<head>
<title>test</title>
<meta charset="utf-8">
</head>
<body>
<div id="test"></div>
</body>
</html>
I think you need clientWidth and clientHeight.
I have a small function the uses a web socket to receive realtime updates. When a new response is received the function prepends a div in the html. I only want the updates to be shown in a window within the page, ie. only ~10 prepended divs should be showing at the most. Ideally I need to pop the oldest div before it overflows out of its parent div.
My question:
How do I pop divs before they overflow the parent? Considering I will receive a response nearly every second or so, what is the most efficient way of doing this?
#HTML
<div class="content">
<p>archienorman-thesis $ realtime_bitcoin</p>
<div id="messages"></div>
<!-- window content -->
</div>
#JS FUNCTION
var total = 0;
var btcs = new WebSocket('wss://ws.blockchain.info/inv');
btcs.onopen = function () {
btcs.send(JSON.stringify({"op": "unconfirmed_sub"}));
};
btcs.onmessage = function (onmsg) {
console.log(response);
var response = JSON.parse(onmsg.data);
var amount = response.x.out[0].value;
var calAmount = amount / 100000000;
var msgs = $('#messages .message');
var count = msgs.length;
if (count == 10) {
msgs.first().remove();
}
$('#messages').prepend("<p class='tx'> Amount: " + calAmount + "</p>");
}
Make the container div overflow: hidden, check if there is overflow using JS scrollHeight and clientHeight.
CSS
#messages {
overflow: hidden;
}
JS
Remove your if statement and add this after your prepend() line:
$('#messages').prepend("<p class='tx'> Amount: " + calAmount + "</p>");
$('#messages').css("overflow", "scroll");
if($('#messages')[0].scrollHeight > $('#messages').height())
msgs.last().remove();
$('#messages').css("overflow", "hidden");
The above quickly makes #messages have the overflow: scroll property in order for the scrollHeight property to work. If there is extra scroll, then it deletes the element.
See Demo.
NOTE
See my comment to your question. You should be removing last(), not first(). See the demo as an example -- try changing last() to first(), and it will not work.
I think something like this should work. This is test code that will basically remove the extra child elements when their combined width exceeds that of the container.
HTML
<div class="container">
<div>1.Test</div>
<div>2.Test</div>
<div>3.Test</div>
<div>4.Test</div>
<div>5.Test</div>
<div>6.Test</div>
<div>7.Test</div>
<div>8.Test</div>
<div>9.Test</div>
<div>10.Test</div>
<div>11.Test</div>
<div>12.Test</div>
<div>13.Test</div>
<div>14.Test</div>
<div>15.Test</div>
</div>
CSS
.container {
width:1000px;
}
.container div {
width: 100px;
display: inline-block;
}
Javascript
function a () {
var containerWidth = $('div.container').width();
var childWidth = $('div.container div').width();
var childCount = $('div.container div').length;
var removeCount = (childWidth * childCount) - containerWidth;
if(removeCount > 0) {
removeCount = Math.floor(removeCount/childWidth);
console.log(removeCount);
for(i = childCount; i > (childCount-removeCount); i--) {
$('div.container div:nth-child('+i+')').remove();
}
}
}
a();
Fiddle: https://jsfiddle.net/L3r2nk6z/5/
I have a div on which I have a directive that binds HTML content and compile it (sort of ng-bing-html directive, but that also compile html to allow insertion of custom directives). The HTML code looks like this :
<div ng-repeat="text in texts">
<div class="content-display"
bind-html-compile="text | filterThatOutputsHTMLCodeWithCustomDirectives | nl2br">
</div>
</div>
The problem is I need to display only a restricted portion of each of the content-display divs, and have a "read more..." button that would expand the corresponding div to its full size. But I CANNOT truncate the text bound in the div, since it's not only text, but can contain HTML tags/directives.
I found this JQuery code, that accomplish what I want visually : https://stackoverflow.com/a/7590517/2459955 (JSFiddle here : http://jsfiddle.net/rlemon/g8c8A/6/ )
The problem is that it's not Angular-compliant, and is pure JQuery. And since my div in which I bind the HTML content is inside an ng-repeat... this solution wouldn't work when the texts array gets refreshed asynchronously.
Do you see a way to have the same behavior as in the answer linked earlier, but being more "Angular compliant" and applying it automatically to each of the content-display divs added by the ng-repeat ?
Consider using a CSS approach like the one described here: https://css-tricks.com/text-fade-read-more/
CSS:
.sidebar-box {
max-height: 120px;
position: relative;
overflow: hidden;
}
.sidebar-box .read-more {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
text-align: center;
margin: 0; padding: 30px 0;
/* "transparent" only works here because == rgba(0,0,0,0) */
background-image: linear-gradient(to bottom, transparent, black);
}
Rather than use jQuery for the read more "reveal", you could create an AngularJS directive for the read more button.
Directive (untested):
angular.module('myApp')
.directive('readMore', readMoreDirective);
function readMoreDirective() {
return function(scope, iElement) {
scope.$on('click', function() {
var totalHeight = 0;
var parentElement = iElement.parent();
var grandparentElement = parentElement.parent();
var parentSiblings = grandparentElement.find("p:not('.read-more')");
// measure how tall inside should be by adding together heights
// of all inside paragraphs (except read-more paragraph)
angular.forEach(parentSiblings, function(ps) {
totalHeight += ps.outerHeight();
});
grandparentElement.css({
// Set height to prevent instant jumpdown when max height is removed
height: grandparentElement.height(),
'max-height': 9999
})
.animate({
height: totalHeight
});
});
};
}
One clean way would be using a class for truncated div, and remove it to display all the text :
Angular scope :
$scope.truncated = []; // make new array containing the state of the div (truncated or not)
for(var i; i < texts.length -1; i++){
$scope.truncated.push(0); // fill it with 0 (false by default)
}
$scope.textTruncate = function(index) {
$scope.truncated[index] = !$scope.truncated[index]; // toggle this value
}
Angular view :
<div ng-repeat="text in texts" ng-class="{truncated: truncated[$index]}">
<div class="content-display"
bind-html-compile="text | filterThatOutputsHTMLCodeWithCustomDirectives | nl2br">
</div>
<button ng-click="textTruncate($index)" >Read more</button>
</div>
CSS :
.content-display {
max-height: 1000px; /* should be your max text height */
overflow: hidden;
transition: max-height .3s ease;
}
.truncated .content-display {
max-height: 100px; /* or whatever max height you need */
}
That is what comes in my mind, not sure if it's the most efficient way.
Try using <p data-dd-collapse-text="100">{{veryLongText}}</p> inside the ng-repeat
Documentation Here
Finally, I ended up using the approach given in this answer with a slight modification : https://stackoverflow.com/a/7590517/2459955
Indeed, since I have a ng-repeat adding more divs into the DOM, the $elem.each() function wouldn't trigger for these additional divs. The solution is to use a JQuery plugin called jquery.initialize.
This plugin gives an $elem.initialize() function that has exactly the same syntax as $elem.each() but initialize() will call the callback again on new items matching the provided selector automatically when they will be added to the DOM. It uses MutationObserver.
The final code looks like this. I have some JQuery code in my module.run() entry (run once at module initialization):
var slideHeight = 400;
$(".content-collapse").initialize(function() {
var $this = $(this);
var $wrap = $this.children(".content-display");
var defHeight = $wrap.height();
if (defHeight >= slideHeight) {
var $readMore = $this.find(".read-more");
var $gradientContainer = $this.find(".gradient-container");
$gradientContainer.append('<div class="gradient"></div>');
$wrap.css("height", slideHeight + "px");
$readMore.append("<a href='#'>Read more</a>");
$readMore.children("a").bind("click", function(event) {
var curHeight = $wrap.height();
if (curHeight == slideHeight) {
$wrap.animate({
height: defHeight
}, "normal");
$(this).text("Read less");
$gradientContainer.children(".gradient").fadeOut();
} else {
$wrap.animate({
height: slideHeight
}, "normal");
$(this).text("Read more");
$gradientContainer.children(".gradient").fadeIn();
}
return false;
});
}
});
And the corresponding HTML (cleaned for demonstration purpose):
<div class="content-collapse" ng-repeat="text in texts">
<div class="content-display" bind-html-compile="::text"></div>
<div class="gradient-container"></div>
<div class="read-more"></div>
</div>
This solution allows for smooth expand/collapse animation that works fine without any CSS hack, it adds the "Read more" button only on answers that exceeds the desired size limit, and works even if the texts array is modified by asynchronous requests.
I had a similar issue. I had o implement this for a data table. I found following directive and it worked smoothly as per requirements:-
Ui Framework- Angular js
In Html
<tr data-ng-repeat="proj in errors">
<td dd-text-collapse dd-text-collapse-max-length="40"
dd-text-collapse-text="{{proj.description}}"></td>
in Javascript:-
app.directive('ddTextCollapse', ['$compile', function($compile) {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
/* start collapsed */
scope.collapsed = false;
/* create the function to toggle the collapse */
scope.toggle = function() {
scope.collapsed = !scope.collapsed;
};
/* wait for changes on the text */
attrs.$observe('ddTextCollapseText', function(text) {
/* get the length from the attributes */
var maxLength = scope.$eval(attrs.ddTextCollapseMaxLength);
if (text.length > maxLength) {
/* split the text in two parts, the first always showing */
var firstPart = String(text).substring(0, maxLength);
var secondPart = String(text).substring(maxLength, text.length);
/* create some new html elements to hold the separate info */
var firstSpan = $compile('<span>' + firstPart + '</span>')(scope);
var secondSpan = $compile('<span ng-if="collapsed">' + secondPart + '</span>')(scope);
var moreIndicatorSpan = $compile('<a ng-if="!collapsed">... </a>')(scope);
var lineBreak = $compile('<br ng-if="collapsed">')(scope);
var toggleButton = $compile('<a class="collapse-text-toggle" ng-click="toggle()">{{collapsed ? "(less)" : "(more)"}}</a>')(scope);
/* remove the current contents of the element
and add the new ones we created */
element.empty();
element.append(firstSpan);
element.append(secondSpan);
element.append(moreIndicatorSpan);
element.append(lineBreak);
element.append(toggleButton);
}
else {
element.empty();
element.append(text);
}
});
}
};
}]);
I have a div id="coding" set on height:300px on CSS.
when I click another div id="menu", I want #coding to change it's height to 800px. I managed to do that like this
<script>
function changec() {
document.getElementById('coding').style.height = "800px";
}
</script>
Now, when click the #menu again, I want the height to get back to it's original 300px value. Can someone help? The code is:
HTML
<div id="coding">
<div id="menu" onclick="changec()">≡</div>
...
</div>
CSS
#coding{
...
height:300px;
}
Simple check if the value is set - remove it (then CSS height will take over).
function changec() {
var xDiv = document.getElementById('coding');
if (xDiv.style.height == '')
xDiv.style.height = '800px'
else
xDiv.style.height = ''
}
Demo: http://jsfiddle.net/ygalanter/BLE6N/
one of the solution for your problem is as follows:
First count how many times you click on #menu
now depending on your expectation you can change the javascript as follows
<script type="text/javascript">
var count = 0;
function changec() {
count++;
if(count%2==1)
document.getElementById("coding").style.height = "800px";
else
document.getElementById("coding").style.height = "300px";
}
</script>
Another alternative solution is
<script type="text/javascript">
function changec() {
var currentheight = document.getElementById('coding').clientHeight;
if (currentheight == 300)
document.getElementById('coding').style.height = "800px";
else if (currentheight == 800)
document.getElementById('coding').style.height = "300px";
}
</script>
Not sure why you tagged jQuery since you didn't use it, but still...Considering the possibility that you are willing to use/learn it, I created a jsFiddle for it: http://jsfiddle.net/Tm2Hd/.
CSS:
#coding{
border:1px solid black; /*optional: Keep track of your div's expand*/
height:300px;
}
#coding.larger{
height:800px;
}
JS:
function changeHeight() {
if($('#coding.larger').length>0)
{
$('#coding').removeClass("larger");
}
else
{
$('#coding').addClass("larger");
}
}
HTML
<div id="coding">
<!--<div onclick="changeHeight()">≡</div>
Personally, I don't suggest using divs as clickable objects... Why don't you use buttons instead?
-->
<button onclick="changeHeight()">≡</button>
...
</div>
My solution to your problem is: Create a new class named larger, pointing to your div, and toggle between this and the original whenever you click the button.
I hope someone can help me with this, I have this javascript code that toggles my body background
function changeDivImage() {
imgPath = document.body.style.backgroundImage;
if (imgPath == "url(images/bg.jpg)" || imgPath == "") {
document.body.style.backgroundImage = "url(images/bg_2.jpg)";
} else {
document.body.style.backgroundImage = "url(images/bg.jpg)";
}
}
I activate it with this link:
change
my problem is that it works fine in IE and firefox, but in chrome, the links work twice then stop working, it basically switches to bg_2.jpg then once clicked again switches back to bg.jpg then it never works again :/
also, is there an easier way to accomplish this? css only maybe? basically i have two body background pictures and i want to be able to click on the link to toggle 1, then click again to toggle 2 instead, then back to 1, etc...
lastly, how can i make the two backgrounds fade in and out? instead of just switch between the two?
Use CSS classes!
CSS Rules
body { background-image: url(images/bg.jpg); }
body.on { background-image: url(images/bg_2.jpg); }
JavaScript:
function changeDivImage() {
$("body").toggleClass("on");
}
If you want to fade, you will end up having to fade the entire page. Use can use jQuery's fadeIn and fadeOut.
Here is your solution:
(This also supports additional images).
var m = 0, imgs = ["images/bg.jpg", "images/bg_2.jpg"];
function changeDivImage()
{
document.body.style.backgroundImage = "url(" + imgs[m] + ")";
m = (m + 1) % imgs.length;
}
Here is the working code on jsFiddle.
Here is the jQuery version on jsFiddle.
UPDATE: CROSS-FADING Version
Here is the cross-fading jQuery version on jsFiddle.
You wouldn't want the whole page (with all elements) to fade in/out. Only the bg should fade. So, this version has a div to be used as the background container. Its z-depth is arranged so that it will keep itself the bottom-most element on the page; and switch between its two children to create the cross-fade effect.
HTML:
<div id="bg">
<div id="bg-top"></div>
<div id="bg-bottom"></div>
</div>
<a id="bg-changer" href="#">change</a>
CSS:
div#bg, div#bg-top, div#bg-bottom
{
display: block;
position: fixed;
width: 100%;
/*height: 500px;*/ /* height is set by javascript on every window resize */
overflow: hidden;
}
div#bg
{
z-index: -99;
}
Javascript (jQuery):
var m = 0,
/* Array of background images. You can add more to it. */
imgs = ["images/bg.jpg", "images/bg_2.jpg"];
/* Toggles the background images with cross-fade effect. */
function changeDivImage()
{
setBgHeight();
var imgTop = imgs[m];
m = (m + 1) % imgs.length;
var imgBottom = imgs[m];
$('div#bg')
.children('#bg-top').show()
.css('background-image', 'url(' + imgTop + ')')
.fadeOut('slow')
.end()
.children('#bg-bottom').hide()
.css('background-image', 'url(' + imgBottom + ')')
.fadeIn('slow');
}
/* Sets the background div height to (fit the) window height. */
function setBgHeight()
{
var h = $(window).height();
$('div#bg').height(h).children().height(h);
}
/* DOM ready event handler. */
$(document).ready(function(event)
{
$('a#bg-changer').click(function(event) { changeDivImage(); });
changeDivImage(); //fade in the first image when the DOM is ready.
});
/* Window resize event handler. */
$(window).resize(function(event)
{
setBgHeight(); //set the background height everytime.
});
This could be improved more but it should give you an idea.
There's a cleaner way to do this. As a demo, see:
<button id="toggle" type="button">Toggle Background Color</button>
var togglebg = (function(){
var bgs = ['black','blue','red','green'];
return function(){
document.body.style.backgroundColor = bgs[0];
bgs.push(bgs.shift());
}
})();
document.getElementById('toggle').onclick = togglebg;
http://jsfiddle.net/userdude/KYDKG/
Obviously, you would replace the Color with Image, but all this does is iterate through a list that's local to the togglebg function, always using the first available. This would also need to run window.onload, preferably as a window.addEventListener/window.attachEvent on the button or elements that will trigger it to run.
Or with jQuery (as I notice the tag now):
jQuery(document).ready(function ($) {
var togglebg = (function () {
var bgs = ['black', 'blue', 'red', 'green'];
return function () {
document.body.style.backgroundColor = bgs[0];
bgs.push(bgs.shift());
}
})();
$('#toggle').on('click', togglebg);
});
http://jsfiddle.net/userdude/KYDKG/1/
And here is a DummyImage version using real images:
jQuery(document).ready(function ($) {
var togglebg = (function () {
var bgs = [
'000/ffffff&text=Black and White',
'0000ff/ffffff&text=Blue and White',
'ffff00/000&text=Yellow and Black',
'ff0000/00ff00&text=Red and Green'
],
url = "url('http://dummyimage.com/600x400/{img}')";
return function () {
document.body.style.backgroundImage = url.replace('{img}', bgs[0]);
bgs.push(bgs.shift());
}
})();
$('#toggle').on('click', togglebg);
});
http://jsfiddle.net/userdude/KYDKG/2/