hoverIntent use id of hovered element to change class - css

I'm trying to reveal content using hoverIntent without writing specific conditions for each id. I would like to have the id passed to the mouse in settings so I can reveal content selected by adding characters to the id + '-x'.
I have tried a few ways to get the div I'm hovering over but these usually end up returning all the information of all the divs with the class "box".
Is there a parent, child thing I should be doing? I don't understand it really but feel like this is the situation it would helpful in.
<div id="id-first-div" class="box">Trigger 1</div>
<div id="id-second-div" class="box">Trigger 2</div>
<div id="id-second-div-x" class="hide">Hidden Bullet 1</div>
<div id="id-first-div-x" class="hide">Hidden Bullet 2</div>
<script>
$(document).ready(function() {
$("#id-first-div").hoverIntent(slide_right_settings);
$("#id-second-div").hoverIntent(slide_right_settings);
});
var slide_right_settings={
sensitivity: 4,
interval: 1500,
timeout: 5000,
over: mousein_triger,
out: mouseout_triger
};
function mousein_triger(){
var id = this.id; // I'm pretty sure I'm going wrong here
$(id + '-x').addClass('reveal');
$(id + '-x').removeClass('hide');
}
function mouseout_triger() {
$(id +'-x').addClass('hide');
$(id +'-x').removeClass('reveal');
}
</script>

//hover intent opening and closing
var slide_right_settings={
over: mousein_triger,
out: mouseout_triger
};
//default id is home
var id = "home";
function mousein_triger(){
//updates id to the one triggering
id = $(this).attr('id');
$('#' + id + '-x').addClass('reveal');
$('#' + id + '-x').removeClass('hide');
}
function mouseout_triger() {
$('#' + id +'-x').addClass('hide');
$('#' + id +'-x').removeClass('reveal');
}
Still not sure if this is the best way to achieve this, but it's working.. I'm sure it could be improved a lot.

place the var id = this.id; outside the function

Related

Making a button that shows or hides multiple images in a random location

I have a problem when I am making the website for one gallery.
I made the code for the button that can show and hide multiple images.
I intend to make the button can place several images in randomly.
I write the code that can function for only one image.
Please tell me the code that functions as a button to place multiple images in a random location.
Users can hide images by pressing the button.
And when users press the button again, it places the images in another random location.
const btn = document.querySelector("button");
const height = document.documentElement.clientHeight;
const width = document.documentElement.clientWidth;
const box = document.getElementById("color");
btn.addEventListener("click", () => {
let randY = Math.floor((Math.random() * height) + 1);
let randX = Math.floor((Math.random() * width) + 1);
box.style.top = randY + "px";
box.style.right = randX + "px";
});
function showhide() {
var x = document.querySelectorAll("#color");
var i;
for (i = 0; i < x.length; i++) {
if (x[i].style.display === "block") {
x[i].style.display = "none";
} else {
x[i].style.display =
"block";
}
}
}
body {
height: 500px;
}
.random {
position: absolute;
}
<button onclick="showhide()" value="Zeige Features" id="button">click me</button>
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/200/200/">
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/200/200/">
You're doing the correct thing in showHide() when using querySelectorAll. You are then able to get all images.
You should never have elements with the same ids. They should be unique. So querySelectorAll("#color") works, but it's now how you should do. Do a querySelector on "img.random" instead.
getElementById only returns a single element, not like querySelectorAll. So you need to use querySelectorAll('img.random').
This might be beyond your knowledge, I don't think you should add the images in HTML, but in javascript code.
a) Add all image paths in an array: ['https://image.com/image.png', ...]
b) Add a single img element. <img id="template" class="random">
c) In javascript code, clone that element for each image path in the array. You can use cloneNode for this.
d) Randomize each position for each element, just like you have done now.
e) Add each element to the DOM through appendChild. Have a unique div that you append to. Be sure to clear it every time second time you hit the button.
f) Solve all bugs along the way. :P
The problem
The main issue here is that you're using getElementById to query #color
const box = document.getElementById("color");
Since getElementById only returns one element (but you have two in your DOM) and the style only applies to one element. That's why you're seeing only one element is randomly moving and the other just stay in the same place.
A side note here, id should be unique in a DOM.
You're in fact using the correct API for the job in the showhide function
var x = document.querySelectorAll("#color");
The fix:
To fix this, you need to query all images by their classname (as suggested in the side note, don't use id for the job)
const boxes = document.querySelectorAll(".random");
Now we have a node list, as you do in the showhide function, we need to loop thru it, I'm not using a for loop here, instead, a forEach loop, it's just more terser and a modern addition to the JS
// Since boxes are not array, we need to covert it to array so we can use that handy `.forEach` here:
Array.from(boxes).forEach(box => {
box.style.top = Math.floor((Math.random() * height) + 1) + "px";
box.style.right = Math.floor((Math.random() * width) + 1) + "px";
})
Now, this should fix your issue. See the complete code below.
const btn = document.querySelector("button");
const height = document.documentElement.clientHeight;
const width = document.documentElement.clientWidth;
const boxes = document.querySelectorAll(".random");
btn.addEventListener("click", () => {
Array.from(boxes).forEach(box => {
box.style.top = Math.floor((Math.random() * height) + 1) + "px";
box.style.right = Math.floor((Math.random() * width) + 1) + "px";
})
});
function showhide() {
var x = document.querySelectorAll(".random");
var i;
for (i = 0; i < x.length; i++) {
if (x[i].style.display === "block") {
x[i].style.display = "none";
} else {
x[i].style.display =
"block";
}
}
}
body {
height: 500px;
}
.random {
position: absolute;
}
<button onclick="showhide()" value="Zeige Features" id="button">click me</button>
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/200/200/">
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/100/100/">

AngularJS C directive using ng-class

The title might not explain what I am trying to achieve, so I will elaborate here.
I have a directive that is restricted to a CSS class name (in this example flex-wrap).
But this class is not applied to the element until we actually have some data.
The HTML for that looks like this:
<div class="row" ng-class="{ 'loading': !controller.loadingRecent, 'flex flex-vertical flex-wrap': controller.recent.length }">
<div class="col-md-12 row-title">
<h1>Recent orders</h1>
</div>
<div class="col-xs-12" ng-if="!controller.recent.length">
<div alert type="danger">
No records have been found that match your search.
</div>
</div>
<div class="col-md-4 tile-lg" ng-repeat="order in controller.recent" tile>
<a class="box-shadow" id="{{ order.orderNumber }}" ui-sref="viewOrder({ orderNumber: order.orderNumber })" coloured-tile>
<div class="text">
<p>
<strong>{{ order.account.accountNumber }}</strong><br />
{{ order.account.name }}<br />
{{ order.raisedBy }}<br />
{{ order.orderNumber }}<br />
{{ controller.getDescription(order) }}<br />
</p>
</div>
</a>
</div>
As you can see, the flex classes are not applied until our recent.length is greater than 0. What I would like to happen is that when we have records, the CSS class is applied and so the angular directive that is associated with that class fires.
Instead, it doesn't do anything at the moment.
Does anyone know how I can get my directive to fire?
Here is my directive, just so you can see it.
.directive('flexWrap', ['$window', '$timeout', function ($window, $timeout) {
// Sets the height of the element
var setHeight = function (element) {
// Declare our variables
var row = element.parent().parent(),
height = 630;
// If our row is a row
if (row.hasClass('row')) {
// Get the height of the rest of the items
height = height - getHeight(row);
}
console.log('height = ' + height);
// Set our elements height
element.css('height', height + 'px');
console.log('we are about to set the width');
// After we set the height, set the width
setWidth(element);
}
// Gets the height to minus off the total
var getHeight = function (element) {
// Declare our variables
var height = 0,
children = element.children(),
loopChildren = element.hasClass('row');
// Loop through the element children
for (var i = 0; i < children.length; i++) {
// Get the child
var child = angular.element(children[i]);
// If the child is not a column
if (!child.hasClass('columns')) {
// If we need to loop the children
if (loopChildren) {
// Get the height of the children
height += getHeight(child);
// Otherwise
} else {
// Add the height of the child to
height += child[0].offsetHeight;
}
}
}
// Return our height
return height;
};
// Sets the width of the element
var setWidth = function (element) {
// After a short period
$timeout(function () {
// Get our last child
var children = element.children(),
length = children.length,
lastChild = children[length - 1];
// Work out the width of the container
var position = element[0].getBoundingClientRect(),
childPosition = lastChild.getBoundingClientRect(),
width = childPosition.left - position.left + childPosition.width;
var style = $window.getComputedStyle(lastChild, null);
console.log(style.getPropertyValue('width'));
console.log('--------------------------------');
console.log(lastChild);
console.log(position);
console.log(childPosition);
console.log(width);
console.log('--------------------------------');
console.log('width = ' + width);
// Apply the width to the element
element.css('width', width + 'px');
}, 500);
};
// Resize the container
var resize = function (element, width) {
// If our width > 992
if (width > 992) {
// Resize our element
setHeight(element);
// Otherwise
} else {
// Set our element width and height to auto
element.css('height', 'auto');
element.css('width', 'auto');
}
};
return {
restrict: 'C',
link: function (scope, element) {
// Get our window
var window = angular.element($window),
width = $window.innerWidth;
// Bind to the resize function
window.bind('resize', function () {
// After half a second
$timeout(function () {
// Get the window width
width = $window.innerWidth;
// Resize our element
resize(element, width);
}, 500);
});
// Initial resize
resize(element, width);
}
};
}]);
Directive declaration style (e.g. restrict: "C") and an ng-class directive are not related to each other at all.
ng-class just adds/removes CSS class - it does not trigger a compilation/link of a directive that might be associated with these classes. In other words, it does not provide a way to dynamically instantiate a directive.
Your directive should handle the situation where data is not yet available. There are a number of ways to achieve that, via $scope.$broadcast/$scope.$on or via a service, or even via $watch - depending on any particular situation.

How to flow a working clock into text?

I am trying to place a live clock into a body of text. I need it to flow as if it were just part of the text, but still be live to the local device. Playing around in Adobe Muse I have been able to get a clock into the text, but it segregates itself to its own line rather than flowing like part of the paragraph.
Following is the code Muse produced. I assume I need to make a change to either actAsInlineDiv normal_text, or actAsDiv excludeFromNormalFlow, or both, but how?
<p id="u3202-10"><span class="Character-Style">You look at the clock on this device and it reads </span><span class="Character-Style"><span class="actAsInlineDiv normal_text" id="u13390"><!-- content --><span class="actAsDiv excludeFromNormalFlow" id="u13388"><!-- custom html --><html>
<head>
<script type="text/javascript">
function startTime()
{
var today=new Date();
var h=today.getHours();
var m=today.getMinutes();
// add a zero in front of numbers<10
m=checkTime(m);
document.getElementById('txt').innerHTML=h+":"+m;
t=setTimeout('startTime()',500);
}
function checkTime(i)
{
if (i<10)
{
i="0" + i;
}
return i;
}
</script>
</head>
<body onload="startTime()">
<div id="txt"></div>
</body>
</html>
</span></span></span><span class="Character-Style">As a result you believe that this is the time. As it happens this is the time but unknown to you your device's clock has stopped functioning and is stuck. Does your true belief that this is the time count as knowledge?</span></p>
I don't know about Muse, but if all you want is a clock of the current time running inline with some text you could do this:
window.onload = displayTime;
function displayTime() {
var element = document.getElementById("clock");
var now = new Date();
var options = {hour: '2-digit', minute:'2-digit'};
element.innerHTML = now.toLocaleTimeString(navigator.language, options);
setTimeout(displayTime, 1000);
}
The current time is <span id="clock"></span> and it's inline with text.
EDIT
I added these two lines to remove the seconds from display as you requested in your comment.
var options = {hour: '2-digit', minute:'2-digit'};
element.innerHTML = now.toLocaleTimeString(navigator.language, options);

Angular nested directive ordering

i am having a hard time finding any information on the ordering of directives and their updating of css properties.
for example, i have two directives, one to set an element to full screen height, and one to align content vertically.
app.directive('fullscreenElement', function() {
return {
restrict: "A",
link: function(scope,element,attrs){
$(element).each(function(){
$(this).css('height', $(window).height());
});
}
};
});
app.directive('alignVertical', function() {
return {
restrict: "A",
link: function(scope,element,attrs){
var height = $(element).height();
var parentHeight = $(element).parent().height();
var padAmount = (parentHeight / 2) - (height / 2);
$(element).css('padding-top', padAmount);
}
};
});
They both work independantly, the trouble is when they are nested, the align-vertical directive doesnt work, im assuming this is because the css height hasn't been set yet? how do i make sure it is set before the alignVertical directive runs? any tips for writing these two directives in a more angular way would be appreciated.
this works:
<header style="height:800px">
<div align-vertical>
this content is centered vertically as expected
</div>
</header>
this doesn't work (content doesnt center vertically, even though header height is now fullscreen):
<header fullscreen-element>
<div align-vertical>
the header element is now fullscreen height but this content is *not* centered vertically
</div>
</header>
thanks
Figured out a solution, posting it here in case anyone finds it helpful.
The trick is to use scope.watch and scope.evalAsync to monitor changes of height to the parent container and run them after rendering is complete.
app.directive('alignVertical', function() {
return {
link: function($scope, element, attrs) {
// Trigger when parent element height changes changes
var watch = $scope.$watch(function() {
return element.parent().height;
}, function() {
// wait for templates to render
$scope.$evalAsync(function() {
// directive runs here after render.
var that = $(element);
var height = that.height();
var parentHeight = that.parent().height();
var padAmount = (parentHeight / 2) - (height / 2);
that.css('padding-top', padAmount);
});
});
},
};
});

Change width on click using Jquery

I have a bootstrap progress bar that changes the current progress when the width attribute is changed. I want to change this width attribute and add 10% when the user toggles it on and decrease 10% when the user toggles it off.
Here is my code:
<div class="progress progress-danger progress-striped active">
<div class="bar" style="width:30%"></div>
</div>
<a id="updateit">Click to change the progress</a>
$(function(){
$("#updateit").toggle(function(){
$('.bar').css("width", + '10%');
});
});
Thanks in advance! :)
Here's a working fiddle
You can't add percentages (I believe), so I converted it using the width of.progress.
0.1 = 10%
$(function(){
$("#updateit").toggle(
function(){
$('.bar').css("width", '+=' + (0.1 * $('.progress').width()));
return false;
},
function(){
$('.bar').css("width", '-=' + (0.1 * $('.progress').width()));
return false;
});
});
The example on the other answer is ok but .bar will finally have a fixed value in pixels. You can try this if you still want to set the value in % (if, in case the parent changed its width, .bar would also change for % values):
$(function(){
var $bar = $(".bar");
$("#updateit").toggle(function(){
$bar.css("width", 100 * parseFloat($bar.css('width')) / parseFloat($bar.parent().css('width')) +10 + '%');
},
function(){
$bar.css("width", 100 * parseFloat($bar.css('width')) / parseFloat($bar.parent().css('width')) -10 + '%');
});
});
I noticed a couple things with your code.
First, make sure you have an href on your anchor. It's proper HTML even if it isn't used (add return false; to your JavaScript to make it not follow the link). My browser didn't recognize the link at all because it didn't have an href.
Next, you want users to click the link and then it toggles the width, right? You'll need the click() event then.
After that, here's what I came up with:
jQuery
var isOn = true;
$(function(){
$("#updateit").click(function(){
console.log(isOn);
if ( isOn ){
isOn = false;
$('.bar').css("width", '10%');
} else {
isOn = true;
$('.bar').css("width", '20%');
}
return false;
});
});​
HTML
<div class="progress progress-danger progress-striped active">
<div class="bar"></div>
</div>
Click to change the progress
​
CSS (used to show the .bar for testing and to set the initial width)
.bar{
width:20%;
height:20px;
background:#600;
}​
The jsFiddle

Resources